summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/add.c2
-rw-r--r--builtin/apply.c147
-rw-r--r--builtin/blame.c4
-rw-r--r--builtin/branch.c8
-rw-r--r--builtin/cat-file.c4
-rw-r--r--builtin/check-attr.c4
-rw-r--r--builtin/check-ignore.c4
-rw-r--r--builtin/check-mailmap.c2
-rw-r--r--builtin/check-ref-format.c2
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c8
-rw-r--r--builtin/clone.c2
-rw-r--r--builtin/column.c2
-rw-r--r--builtin/commit.c8
-rw-r--r--builtin/config.c2
-rw-r--r--builtin/describe.c4
-rw-r--r--builtin/diff-files.c2
-rw-r--r--builtin/diff-index.c2
-rw-r--r--builtin/diff-tree.c2
-rw-r--r--builtin/fetch-pack.c2
-rw-r--r--builtin/fetch.c6
-rw-r--r--builtin/fmt-merge-msg.c2
-rw-r--r--builtin/for-each-ref.c9
-rw-r--r--builtin/fsck.c2
-rw-r--r--builtin/gc.c2
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/hash-object.c2
-rw-r--r--builtin/help.c2
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/log.c4
-rw-r--r--builtin/ls-files.c2
-rw-r--r--builtin/ls-remote.c2
-rw-r--r--builtin/mailinfo.c2
-rw-r--r--builtin/merge-base.c4
-rw-r--r--builtin/merge-file.c4
-rw-r--r--builtin/merge-index.c2
-rw-r--r--builtin/merge.c4
-rw-r--r--builtin/mv.c2
-rw-r--r--builtin/name-rev.c6
-rw-r--r--builtin/notes.c24
-rw-r--r--builtin/pack-redundant.c2
-rw-r--r--builtin/pack-refs.c2
-rw-r--r--builtin/prune-packed.c2
-rw-r--r--builtin/push.c5
-rw-r--r--builtin/receive-pack.c234
-rw-r--r--builtin/reflog.c259
-rw-r--r--builtin/remote.c4
-rw-r--r--builtin/repack.c2
-rw-r--r--builtin/replace.c2
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/rev-parse.c6
-rw-r--r--builtin/revert.c4
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/send-pack.c6
-rw-r--r--builtin/shortlog.c2
-rw-r--r--builtin/show-branch.c4
-rw-r--r--builtin/show-ref.c2
-rw-r--r--builtin/symbolic-ref.c4
-rw-r--r--builtin/tag.c6
-rw-r--r--builtin/update-index.c2
-rw-r--r--builtin/update-ref.c26
-rw-r--r--builtin/verify-commit.c2
-rw-r--r--builtin/verify-pack.c2
-rw-r--r--builtin/verify-tag.c2
64 files changed, 548 insertions, 334 deletions
diff --git a/builtin/add.c b/builtin/add.c
index 1074e32349..3390933d68 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -19,7 +19,7 @@
#include "argv-array.h"
static const char * const builtin_add_usage[] = {
- N_("git add [options] [--] <pathspec>..."),
+ N_("git add [<options>] [--] <pathspec>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
diff --git a/builtin/apply.c b/builtin/apply.c
index c484b53f55..65b97eee69 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -51,11 +51,12 @@ static int apply_verbosely;
static int allow_overlap;
static int no_add;
static int threeway;
+static int unsafe_paths;
static const char *fake_ancestor;
static int line_termination = '\n';
static unsigned int p_context = UINT_MAX;
static const char * const apply_usage[] = {
- N_("git apply [options] [<patch>...]"),
+ N_("git apply [<options>] [<patch>...]"),
NULL
};
@@ -1600,6 +1601,9 @@ static int parse_fragment(const char *line, unsigned long size,
if (!deleted && !added)
leading++;
trailing++;
+ if (!apply_in_reverse &&
+ ws_error_action == correct_ws_error)
+ check_whitespace(line, len, patch->ws_rule);
break;
case '-':
if (apply_in_reverse &&
@@ -3221,7 +3225,7 @@ static int load_patch_target(struct strbuf *buf,
const char *name,
unsigned expected_mode)
{
- if (cached) {
+ if (cached || check_index) {
if (read_file_or_gitlink(ce, buf))
return error(_("read of %s failed"), name);
} else if (name) {
@@ -3230,6 +3234,8 @@ static int load_patch_target(struct strbuf *buf,
return read_file_or_gitlink(ce, buf);
else
return SUBMODULE_PATCH_WITHOUT_INDEX;
+ } else if (has_symlink_leading_path(name, strlen(name))) {
+ return error(_("reading from '%s' beyond a symbolic link"), name);
} else {
if (read_old_data(st, name, buf))
return error(_("read of %s failed"), name);
@@ -3570,6 +3576,121 @@ static int check_to_create(const char *new_name, int ok_if_exists)
}
/*
+ * We need to keep track of how symlinks in the preimage are
+ * manipulated by the patches. A patch to add a/b/c where a/b
+ * is a symlink should not be allowed to affect the directory
+ * the symlink points at, but if the same patch removes a/b,
+ * it is perfectly fine, as the patch removes a/b to make room
+ * to create a directory a/b so that a/b/c can be created.
+ */
+static struct string_list symlink_changes;
+#define SYMLINK_GOES_AWAY 01
+#define SYMLINK_IN_RESULT 02
+
+static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
+{
+ struct string_list_item *ent;
+
+ ent = string_list_lookup(&symlink_changes, path);
+ if (!ent) {
+ ent = string_list_insert(&symlink_changes, path);
+ ent->util = (void *)0;
+ }
+ ent->util = (void *)(what | ((uintptr_t)ent->util));
+ return (uintptr_t)ent->util;
+}
+
+static uintptr_t check_symlink_changes(const char *path)
+{
+ struct string_list_item *ent;
+
+ ent = string_list_lookup(&symlink_changes, path);
+ if (!ent)
+ return 0;
+ return (uintptr_t)ent->util;
+}
+
+static void prepare_symlink_changes(struct patch *patch)
+{
+ for ( ; patch; patch = patch->next) {
+ if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
+ (patch->is_rename || patch->is_delete))
+ /* the symlink at patch->old_name is removed */
+ register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
+
+ if (patch->new_name && S_ISLNK(patch->new_mode))
+ /* the symlink at patch->new_name is created or remains */
+ register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
+ }
+}
+
+static int path_is_beyond_symlink_1(struct strbuf *name)
+{
+ do {
+ unsigned int change;
+
+ while (--name->len && name->buf[name->len] != '/')
+ ; /* scan backwards */
+ if (!name->len)
+ break;
+ name->buf[name->len] = '\0';
+ change = check_symlink_changes(name->buf);
+ if (change & SYMLINK_IN_RESULT)
+ return 1;
+ if (change & SYMLINK_GOES_AWAY)
+ /*
+ * This cannot be "return 0", because we may
+ * see a new one created at a higher level.
+ */
+ continue;
+
+ /* otherwise, check the preimage */
+ if (check_index) {
+ struct cache_entry *ce;
+
+ ce = cache_file_exists(name->buf, name->len, ignore_case);
+ if (ce && S_ISLNK(ce->ce_mode))
+ return 1;
+ } else {
+ struct stat st;
+ if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
+ return 1;
+ }
+ } while (1);
+ return 0;
+}
+
+static int path_is_beyond_symlink(const char *name_)
+{
+ int ret;
+ struct strbuf name = STRBUF_INIT;
+
+ assert(*name_ != '\0');
+ strbuf_addstr(&name, name_);
+ ret = path_is_beyond_symlink_1(&name);
+ strbuf_release(&name);
+
+ return ret;
+}
+
+static void die_on_unsafe_path(struct patch *patch)
+{
+ const char *old_name = NULL;
+ const char *new_name = NULL;
+ if (patch->is_delete)
+ old_name = patch->old_name;
+ else if (!patch->is_new && !patch->is_copy)
+ old_name = patch->old_name;
+ if (!patch->is_delete)
+ new_name = patch->new_name;
+
+ if (old_name && !verify_path(old_name))
+ die(_("invalid path '%s'"), old_name);
+ if (new_name && !verify_path(new_name))
+ die(_("invalid path '%s'"), new_name);
+}
+
+/*
* Check and apply the patch in-core; leave the result in patch->result
* for the caller to write it out to the final destination.
*/
@@ -3656,6 +3777,22 @@ static int check_patch(struct patch *patch)
}
}
+ if (!unsafe_paths)
+ die_on_unsafe_path(patch);
+
+ /*
+ * An attempt to read from or delete a path that is beyond a
+ * symbolic link will be prevented by load_patch_target() that
+ * is called at the beginning of apply_data() so we do not
+ * have to worry about a patch marked with "is_delete" bit
+ * here. We however need to make sure that the patch result
+ * is not deposited to a path that is beyond a symbolic link
+ * here.
+ */
+ if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
+ return error(_("affected file '%s' is beyond a symbolic link"),
+ patch->new_name);
+
if (apply_data(patch, &st, ce) < 0)
return error(_("%s: patch does not apply"), name);
patch->rejected = 0;
@@ -3666,6 +3803,7 @@ static int check_patch_list(struct patch *patch)
{
int err = 0;
+ prepare_symlink_changes(patch);
prepare_fn_table(patch);
while (patch) {
if (apply_verbosely)
@@ -4404,6 +4542,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
N_("make sure the patch is applicable to the current index")),
OPT_BOOL(0, "cached", &cached,
N_("apply a patch without touching the working tree")),
+ OPT_BOOL(0, "unsafe-paths", &unsafe_paths,
+ N_("accept a patch that touches outside the working area")),
OPT_BOOL(0, "apply", &force_apply,
N_("also apply the patch (use with --stat/--summary/--check)")),
OPT_BOOL('3', "3way", &threeway,
@@ -4476,6 +4616,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
die(_("--cached outside a repository"));
check_index = 1;
}
+ if (check_index)
+ unsafe_paths = 0;
+
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
int fd;
diff --git a/builtin/blame.c b/builtin/blame.c
index 2b1f9dd6cd..06484c2e0e 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -27,12 +27,12 @@
#include "line-range.h"
#include "line-log.h"
-static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
+static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] file");
static const char *blame_opt_usage[] = {
blame_usage,
"",
- N_("[rev-opts] are documented in git-rev-list(1)"),
+ N_("<rev-opts> are documented in git-rev-list(1)"),
NULL
};
diff --git a/builtin/branch.c b/builtin/branch.c
index dc6f0b266c..6a25957e9f 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -21,10 +21,10 @@
#include "wt-status.h"
static const char * const builtin_branch_usage[] = {
- N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
- N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
- N_("git branch [options] [-r] (-d | -D) <branchname>..."),
- N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
+ N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
+ N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
+ N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
+ N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
NULL
};
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 31b133b357..df99df4db1 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -323,8 +323,8 @@ static int batch_objects(struct batch_options *opt)
}
static const char * const cat_file_usage[] = {
- N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
- N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
+ N_("git cat-file (-t | -s | -e | -p | <type> | --textconv) <object>"),
+ N_("git cat-file (--batch | --batch-check) < <list-of-objects>"),
NULL
};
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 5600ec3f61..21d2bedcc9 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -8,8 +8,8 @@ static int all_attrs;
static int cached_attrs;
static int stdin_paths;
static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | attr...] [--] pathname..."),
-N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
+N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [-a | --all | <attr>...] < <list-of-paths>"),
NULL
};
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
index 594463a11b..dc8d97c56c 100644
--- a/builtin/check-ignore.c
+++ b/builtin/check-ignore.c
@@ -7,8 +7,8 @@
static int quiet, verbose, stdin_paths, show_non_matching, no_index;
static const char * const check_ignore_usage[] = {
-"git check-ignore [options] pathname...",
-"git check-ignore [options] --stdin < <list-of-paths>",
+"git check-ignore [<options>] <pathname>...",
+"git check-ignore [<options>] --stdin < <list-of-paths>",
NULL
};
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
index 8f4d809bd8..eaaea546d3 100644
--- a/builtin/check-mailmap.c
+++ b/builtin/check-mailmap.c
@@ -5,7 +5,7 @@
static int use_stdin;
static const char * const check_mailmap_usage[] = {
-N_("git check-mailmap [options] <contact>..."),
+N_("git check-mailmap [<options>] <contact>..."),
NULL
};
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 28a7320271..fd915d5984 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -8,7 +8,7 @@
#include "strbuf.h"
static const char builtin_check_ref_format_usage[] =
-"git check-ref-format [--normalize] [options] <refname>\n"
+"git check-ref-format [--normalize] [<options>] <refname>\n"
" or: git check-ref-format --branch <branchname-shorthand>";
/*
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index 031780f49e..9ca2da1583 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length)
}
static const char * const builtin_checkout_index_usage[] = {
- N_("git checkout-index [options] [--] [<file>...]"),
+ N_("git checkout-index [<options>] [--] [<file>...]"),
NULL
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 52d6cbb0a8..3e141fc149 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -22,8 +22,8 @@
#include "argv-array.h"
static const char * const checkout_usage[] = {
- N_("git checkout [options] <branch>"),
- N_("git checkout [options] [<branch>] -- <file>..."),
+ N_("git checkout [<options>] <branch>"),
+ N_("git checkout [<options>] [<branch>] -- <file>..."),
NULL,
};
@@ -746,7 +746,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
_(
"If you want to keep them by creating a new branch, "
"this may be a good time\nto do so with:\n\n"
- " git branch new_branch_name %s\n\n"),
+ " git branch <new-branch-name> %s\n\n"),
find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
}
@@ -1127,7 +1127,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
- N_("second guess 'git checkout no-such-branch'")),
+ N_("second guess 'git checkout <no-such-branch>'")),
OPT_END(),
};
diff --git a/builtin/clone.c b/builtin/clone.c
index 316c75d0b3..957246723e 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -34,7 +34,7 @@
*
*/
static const char * const builtin_clone_usage[] = {
- N_("git clone [options] [--] <repo> [<dir>]"),
+ N_("git clone [<options>] [--] <repo> [<dir>]"),
NULL
};
diff --git a/builtin/column.c b/builtin/column.c
index 75818520e1..449413c8a8 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -6,7 +6,7 @@
#include "column.h"
static const char * const builtin_column_usage[] = {
- N_("git column [options]"),
+ N_("git column [<options>]"),
NULL
};
static unsigned int colopts;
diff --git a/builtin/commit.c b/builtin/commit.c
index 714638c5d6..961e467242 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -34,12 +34,12 @@
#include "mailmap.h"
static const char * const builtin_commit_usage[] = {
- N_("git commit [options] [--] <pathspec>..."),
+ N_("git commit [<options>] [--] <pathspec>..."),
NULL
};
static const char * const builtin_status_usage[] = {
- N_("git status [options] [--] <pathspec>..."),
+ N_("git status [<options>] [--] <pathspec>..."),
NULL
};
@@ -1766,8 +1766,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
if (!transaction ||
ref_transaction_update(transaction, "HEAD", sha1,
current_head
- ? current_head->object.sha1 : NULL,
- 0, !!current_head, sb.buf, &err) ||
+ ? current_head->object.sha1 : null_sha1,
+ 0, sb.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
rollback_index_files();
die("%s", err.buf);
diff --git a/builtin/config.c b/builtin/config.c
index 15a7bea936..d32c5327e5 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -5,7 +5,7 @@
#include "urlmatch.h"
static const char *const builtin_config_usage[] = {
- N_("git config [options]"),
+ N_("git config [<options>]"),
NULL
};
diff --git a/builtin/describe.c b/builtin/describe.c
index 9103193b4f..e00a75b121 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -14,8 +14,8 @@
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
- N_("git describe [options] <commit-ish>*"),
- N_("git describe [options] --dirty"),
+ N_("git describe [<options>] [<commit-ish>...]"),
+ N_("git describe [<options>] --dirty"),
NULL
};
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
index 9200069363..8ed2eb8813 100644
--- a/builtin/diff-files.c
+++ b/builtin/diff-files.c
@@ -11,7 +11,7 @@
#include "submodule.h"
static const char diff_files_usage[] =
-"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_files(int argc, const char **argv, const char *prefix)
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
index ce15b23042..d979824f93 100644
--- a/builtin/diff-index.c
+++ b/builtin/diff-index.c
@@ -7,7 +7,7 @@
static const char diff_cache_usage[] =
"git diff-index [-m] [--cached] "
-"[<common diff options>] <tree-ish> [<path>...]"
+"[<common-diff-options>] <tree-ish> [<path>...]"
COMMON_DIFF_OPTIONS_HELP;
int cmd_diff_index(int argc, const char **argv, const char *prefix)
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 1c4ad6223e..12b683d021 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -82,7 +82,7 @@ static int diff_tree_stdin(char *line)
static const char diff_tree_usage[] =
"git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
" -r diff recursively\n"
" --root include the initial commit as diff against /dev/null\n"
COMMON_DIFF_OPTIONS_HELP;
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index 1262b405f8..4a6b340ab6 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -6,7 +6,7 @@
#include "sha1-array.h"
static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] "
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 75a55e590b..f9512652cf 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -415,8 +415,10 @@ static int s_update_ref(const char *action,
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref->name, ref->new_sha1,
- ref->old_sha1, 0, check_old, msg, &err))
+ ref_transaction_update(transaction, ref->name,
+ ref->new_sha1,
+ check_old ? ref->old_sha1 : NULL,
+ 0, msg, &err))
goto fail;
ret = ref_transaction_commit(transaction, &err);
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index af7919e51e..1d962dc569 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -10,7 +10,7 @@
#include "gpg-interface.h"
static const char * const fmt_merge_msg_usage[] = {
- N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
+ N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
NULL
};
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index a0123f6146..83f9cf9163 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -178,11 +178,10 @@ static const char *find_next(const char *cp)
static int verify_format(const char *format)
{
const char *cp, *sp;
- static const char color_reset[] = "color:reset";
need_color_reset_at_eol = 0;
for (cp = format; *cp && (sp = find_next(cp)); ) {
- const char *ep = strchr(sp, ')');
+ const char *color, *ep = strchr(sp, ')');
int at;
if (!ep)
@@ -191,8 +190,8 @@ static int verify_format(const char *format)
at = parse_atom(sp + 2, ep);
cp = ep + 1;
- if (starts_with(used_atom[at], "color:"))
- need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset);
+ if (skip_prefix(used_atom[at], "color:", &color))
+ need_color_reset_at_eol = !!strcmp(color, "reset");
}
return 0;
}
@@ -1061,7 +1060,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
}
static char const * const for_each_ref_usage[] = {
- N_("git for-each-ref [options] [<pattern>]"),
+ N_("git for-each-ref [<options>] [<pattern>]"),
NULL
};
diff --git a/builtin/fsck.c b/builtin/fsck.c
index a27515aeaa..0c757862e8 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -600,7 +600,7 @@ static int fsck_cache_tree(struct cache_tree *it)
}
static char const * const fsck_usage[] = {
- N_("git fsck [options] [<object>...]"),
+ N_("git fsck [<options>] [<object>...]"),
NULL
};
diff --git a/builtin/gc.c b/builtin/gc.c
index 005adbebea..5c634afc00 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -21,7 +21,7 @@
#define FAILED_RUN "failed to run %s"
static const char * const builtin_gc_usage[] = {
- N_("git gc [options]"),
+ N_("git gc [<options>]"),
NULL
};
diff --git a/builtin/grep.c b/builtin/grep.c
index 4063882f06..9262b73b6f 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -20,7 +20,7 @@
#include "pathspec.h"
static char const * const grep_usage[] = {
- N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
+ N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
NULL
};
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 6158363318..207b90c7b1 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -79,7 +79,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
int cmd_hash_object(int argc, const char **argv, const char *prefix)
{
static const char * const hash_object_usage[] = {
- N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+ N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
N_("git hash-object --stdin-paths < <list-of-paths>"),
NULL
};
diff --git a/builtin/help.c b/builtin/help.c
index e78c135e01..6133fe496b 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -49,7 +49,7 @@ static struct option builtin_help_options[] = {
};
static const char * const builtin_help_usage[] = {
- N_("git help [--all] [--guides] [--man|--web|--info] [command]"),
+ N_("git help [--all] [--guides] [--man | --web | --info] [<command>]"),
NULL
};
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 9966522b4a..6723d39c3b 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -472,7 +472,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
}
static const char *const init_db_usage[] = {
- N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
+ N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
NULL
};
diff --git a/builtin/log.c b/builtin/log.c
index a131992c52..dd8f3fcfc4 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -39,7 +39,7 @@ static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
N_("git log [<options>] [<revision range>] [[--] <path>...]"),
- N_("git show [options] <object>..."),
+ N_("git show [<options>] <object>..."),
NULL
};
@@ -1023,7 +1023,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
}
static const char * const builtin_format_patch_usage[] = {
- N_("git format-patch [options] [<since> | <revision range>]"),
+ N_("git format-patch [<options>] [<since> | <revision-range>]"),
NULL
};
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 99cee20fb0..914054d367 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -398,7 +398,7 @@ int report_path_error(const char *ps_matched,
}
static const char * const ls_files_usage[] = {
- N_("git ls-files [options] [<file>...]"),
+ N_("git ls-files [<options>] [<file>...]"),
NULL
};
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index b2a4b92992..4554dbc8a9 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -5,7 +5,7 @@
static const char ls_remote_usage[] =
"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n"
-" [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
+" [-q | --quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
/*
* Is there one among the list of patterns that match the tail part
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index c8a47c173d..999a5250fb 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -1031,7 +1031,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)
}
static const char mailinfo_usage[] =
- "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
+ "git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
{
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index fdebef6fa1..08a8217890 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -26,8 +26,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
}
static const char * const merge_base_usage[] = {
- N_("git merge-base [-a|--all] <commit> <commit>..."),
- N_("git merge-base [-a|--all] --octopus <commit>..."),
+ N_("git merge-base [-a | --all] <commit> <commit>..."),
+ N_("git merge-base [-a | --all] --octopus <commit>..."),
N_("git merge-base --independent <commit>..."),
N_("git merge-base --is-ancestor <commit> <commit>"),
N_("git merge-base --fork-point <ref> [<commit>]"),
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 232b76857c..ea8093f676 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -5,7 +5,7 @@
#include "parse-options.h"
static const char *const merge_file_usage[] = {
- N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
+ N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
NULL
};
@@ -42,7 +42,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
N_("for conflicts, use this marker size")),
OPT__QUIET(&quiet, N_("do not warn about conflicts")),
OPT_CALLBACK('L', NULL, names, N_("name"),
- N_("set labels for file1/orig_file/file2"), &label_cb),
+ N_("set labels for file1/orig-file/file2"), &label_cb),
OPT_END(),
};
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
index b416d92849..1a1eafa6fd 100644
--- a/builtin/merge-index.c
+++ b/builtin/merge-index.c
@@ -75,7 +75,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
signal(SIGCHLD, SIG_DFL);
if (argc < 3)
- usage("git merge-index [-o] [-q] <merge-program> (-a | [--] <filename>*)");
+ usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
read_cache();
diff --git a/builtin/merge.c b/builtin/merge.c
index c638fd5a9a..3b0f8f96d4 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -42,8 +42,8 @@ struct strategy {
};
static const char * const builtin_merge_usage[] = {
- N_("git merge [options] [<commit>...]"),
- N_("git merge [options] <msg> HEAD <commit>"),
+ N_("git merge [<options>] [<commit>...]"),
+ N_("git merge [<options>] <msg> HEAD <commit>"),
N_("git merge --abort"),
NULL
};
diff --git a/builtin/mv.c b/builtin/mv.c
index 563d05ba1a..d1d43168ae 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -12,7 +12,7 @@
#include "submodule.h"
static const char * const builtin_mv_usage[] = {
- N_("git mv [options] <source>... <destination>"),
+ N_("git mv [<options>] <source>... <destination>"),
NULL
};
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 3c8f319be6..9736d4452f 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -252,9 +252,9 @@ static void show_name(const struct object *obj,
}
static char const * const name_rev_usage[] = {
- N_("git name-rev [options] <commit>..."),
- N_("git name-rev [options] --all"),
- N_("git name-rev [options] --stdin"),
+ N_("git name-rev [<options>] <commit>..."),
+ N_("git name-rev [<options>] --all"),
+ N_("git name-rev [<options>] --stdin"),
NULL
};
diff --git a/builtin/notes.c b/builtin/notes.c
index a9f37d0456..63f95fc554 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -21,18 +21,18 @@
#include "notes-utils.h"
static const char * const git_notes_usage[] = {
- N_("git notes [--ref <notes_ref>] [list [<object>]]"),
- N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
- N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
- N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
- N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"),
- N_("git notes [--ref <notes_ref>] show [<object>]"),
- N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
+ N_("git notes [--ref <notes-ref>] [list [<object>]]"),
+ N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
+ N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
+ N_("git notes [--ref <notes-ref>] show [<object>]"),
+ N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
N_("git notes merge --commit [-v | -q]"),
N_("git notes merge --abort [-v | -q]"),
- N_("git notes [--ref <notes_ref>] remove [<object>...]"),
- N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
- N_("git notes [--ref <notes_ref>] get-ref"),
+ N_("git notes [--ref <notes-ref>] remove [<object>...]"),
+ N_("git notes [--ref <notes-ref>] prune [-n | -v]"),
+ N_("git notes [--ref <notes-ref>] get-ref"),
NULL
};
@@ -68,7 +68,7 @@ static const char * const git_notes_show_usage[] = {
};
static const char * const git_notes_merge_usage[] = {
- N_("git notes merge [<options>] <notes_ref>"),
+ N_("git notes merge [<options>] <notes-ref>"),
N_("git notes merge --commit [<options>]"),
N_("git notes merge --abort [<options>]"),
NULL
@@ -951,7 +951,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
const char *override_notes_ref = NULL;
struct option options[] = {
OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
- N_("use notes from <notes_ref>")),
+ N_("use notes from <notes-ref>")),
OPT_END()
};
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 649c3aaa93..d0532f66b1 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -11,7 +11,7 @@
#define BLKSIZE 512
static const char pack_redundant_usage[] =
-"git pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
+"git pack-redundant [--verbose] [--alt-odb] (--all | <filename.pack>...)";
static int load_all_packs, verbose, alt_odb;
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
index b20b1ec4c1..39f9a55d16 100644
--- a/builtin/pack-refs.c
+++ b/builtin/pack-refs.c
@@ -3,7 +3,7 @@
#include "refs.h"
static char const * const pack_refs_usage[] = {
- N_("git pack-refs [options]"),
+ N_("git pack-refs [<options>]"),
NULL
};
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index f24a2c2bdc..7cf900ea07 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -4,7 +4,7 @@
#include "parse-options.h"
static const char * const prune_packed_usage[] = {
- N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
+ N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
NULL
};
diff --git a/builtin/push.c b/builtin/push.c
index 12f5e69393..fc771a9f6f 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -487,6 +487,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
int flags = 0;
int tags = 0;
int rc;
+ int atomic = 0;
const char *repo = NULL; /* default repository */
struct option options[] = {
OPT__VERBOSITY(&verbosity),
@@ -518,6 +519,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
TRANSPORT_PUSH_FOLLOW_TAGS),
OPT_BIT(0, "signed", &flags, N_("GPG sign the push"), TRANSPORT_PUSH_CERT),
+ OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
OPT_END()
};
@@ -533,6 +535,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
if (tags)
add_refspec("refs/tags/*");
+ if (atomic)
+ flags |= TRANSPORT_PUSH_ATOMIC;
+
if (argc > 0) {
repo = argv[0];
set_refspecs(argv + 1, argc - 1, repo);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 8266c1fccf..70e9ce5f96 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -38,9 +38,11 @@ static int receive_fsck_objects = -1;
static int transfer_fsck_objects = -1;
static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
+static int advertise_atomic_push = 1;
static int unpack_limit = 100;
static int report_status;
static int use_sideband;
+static int use_atomic;
static int quiet;
static int prefer_ofs_delta = 1;
static int auto_update_server_info;
@@ -67,6 +69,7 @@ static const char *NONCE_SLOP = "SLOP";
static const char *nonce_status;
static long nonce_stamp_slop;
static unsigned long nonce_stamp_slop_limit;
+static struct ref_transaction *transaction;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
@@ -160,6 +163,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
return 0;
}
+ if (strcmp(var, "receive.advertiseatomic") == 0) {
+ advertise_atomic_push = git_config_bool(var, value);
+ return 0;
+ }
+
return git_default_config(var, value, cb);
}
@@ -175,6 +183,8 @@ static void show_ref(const char *path, const unsigned char *sha1)
strbuf_addstr(&cap,
"report-status delete-refs side-band-64k quiet");
+ if (advertise_atomic_push)
+ strbuf_addstr(&cap, " atomic");
if (prefer_ofs_delta)
strbuf_addstr(&cap, " ofs-delta");
if (push_cert_nonce)
@@ -733,7 +743,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
return 0;
}
-static const char *update_worktree(unsigned char *sha1)
+static const char *push_to_deploy(unsigned char *sha1,
+ struct argv_array *env,
+ const char *work_tree)
{
const char *update_refresh[] = {
"update-index", "-q", "--ignore-submodules", "--refresh", NULL
@@ -748,69 +760,87 @@ static const char *update_worktree(unsigned char *sha1)
const char *read_tree[] = {
"read-tree", "-u", "-m", NULL, NULL
};
- const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
- struct argv_array env = ARGV_ARRAY_INIT;
struct child_process child = CHILD_PROCESS_INIT;
- if (is_bare_repository())
- return "denyCurrentBranch = updateInstead needs a worktree";
-
- argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
-
child.argv = update_refresh;
- child.env = env.argv;
+ child.env = env->argv;
child.dir = work_tree;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
- if (run_command(&child)) {
- argv_array_clear(&env);
+ if (run_command(&child))
return "Up-to-date check failed";
- }
/* run_command() does not clean up completely; reinitialize */
child_process_init(&child);
child.argv = diff_files;
- child.env = env.argv;
+ child.env = env->argv;
child.dir = work_tree;
child.no_stdin = 1;
child.stdout_to_stderr = 1;
child.git_cmd = 1;
- if (run_command(&child)) {
- argv_array_clear(&env);
+ if (run_command(&child))
return "Working directory has unstaged changes";
- }
child_process_init(&child);
child.argv = diff_index;
- child.env = env.argv;
+ child.env = env->argv;
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
child.git_cmd = 1;
- if (run_command(&child)) {
- argv_array_clear(&env);
+ if (run_command(&child))
return "Working directory has staged changes";
- }
read_tree[3] = sha1_to_hex(sha1);
child_process_init(&child);
child.argv = read_tree;
- child.env = env.argv;
+ child.env = env->argv;
child.dir = work_tree;
child.no_stdin = 1;
child.no_stdout = 1;
child.stdout_to_stderr = 0;
child.git_cmd = 1;
- if (run_command(&child)) {
- argv_array_clear(&env);
+ if (run_command(&child))
return "Could not update working tree to new HEAD";
- }
- argv_array_clear(&env);
return NULL;
}
+static const char *push_to_checkout_hook = "push-to-checkout";
+
+static const char *push_to_checkout(unsigned char *sha1,
+ struct argv_array *env,
+ const char *work_tree)
+{
+ argv_array_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
+ if (run_hook_le(env->argv, push_to_checkout_hook,
+ sha1_to_hex(sha1), NULL))
+ return "push-to-checkout hook declined";
+ else
+ return NULL;
+}
+
+static const char *update_worktree(unsigned char *sha1)
+{
+ const char *retval;
+ const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+ struct argv_array env = ARGV_ARRAY_INIT;
+
+ if (is_bare_repository())
+ return "denyCurrentBranch = updateInstead needs a worktree";
+
+ argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+ if (!find_hook(push_to_checkout_hook))
+ retval = push_to_deploy(sha1, &env, work_tree);
+ else
+ retval = push_to_checkout(sha1, &env, work_tree);
+
+ argv_array_clear(&env);
+ return retval;
+}
+
static const char *update(struct command *cmd, struct shallow_info *si)
{
const char *name = cmd->ref_name;
@@ -910,6 +940,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
if (is_null_sha1(new_sha1)) {
+ struct strbuf err = STRBUF_INIT;
if (!parse_object(old_sha1)) {
old_sha1 = NULL;
if (ref_exists(name)) {
@@ -919,35 +950,35 @@ static const char *update(struct command *cmd, struct shallow_info *si)
cmd->did_not_exist = 1;
}
}
- if (delete_ref(namespaced_name, old_sha1, 0)) {
- rp_error("failed to delete %s", name);
+ if (ref_transaction_delete(transaction,
+ namespaced_name,
+ old_sha1,
+ 0, "push", &err)) {
+ rp_error("%s", err.buf);
+ strbuf_release(&err);
return "failed to delete";
}
+ strbuf_release(&err);
return NULL; /* good */
}
else {
struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
-
if (shallow_update && si->shallow_ref[cmd->index] &&
update_shallow_ref(cmd, si))
return "shallow error";
- transaction = ref_transaction_begin(&err);
- if (!transaction ||
- ref_transaction_update(transaction, namespaced_name,
- new_sha1, old_sha1, 0, 1, "push",
- &err) ||
- ref_transaction_commit(transaction, &err)) {
- ref_transaction_free(transaction);
-
+ if (ref_transaction_update(transaction,
+ namespaced_name,
+ new_sha1, old_sha1,
+ 0, "push",
+ &err)) {
rp_error("%s", err.buf);
strbuf_release(&err);
+
return "failed to update ref";
}
-
- ref_transaction_free(transaction);
strbuf_release(&err);
+
return NULL; /* good */
}
}
@@ -1131,11 +1162,105 @@ static void reject_updates_to_hidden(struct command *commands)
}
}
+static int should_process_cmd(struct command *cmd)
+{
+ return !cmd->error_string && !cmd->skip_update;
+}
+
+static void warn_if_skipped_connectivity_check(struct command *commands,
+ struct shallow_info *si)
+{
+ struct command *cmd;
+ int checked_connectivity = 1;
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (should_process_cmd(cmd) && si->shallow_ref[cmd->index]) {
+ error("BUG: connectivity check has not been run on ref %s",
+ cmd->ref_name);
+ checked_connectivity = 0;
+ }
+ }
+ if (!checked_connectivity)
+ die("BUG: connectivity check skipped???");
+}
+
+static void execute_commands_non_atomic(struct command *commands,
+ struct shallow_info *si)
+{
+ struct command *cmd;
+ struct strbuf err = STRBUF_INIT;
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!should_process_cmd(cmd))
+ continue;
+
+ transaction = ref_transaction_begin(&err);
+ if (!transaction) {
+ rp_error("%s", err.buf);
+ strbuf_reset(&err);
+ cmd->error_string = "transaction failed to start";
+ continue;
+ }
+
+ cmd->error_string = update(cmd, si);
+
+ if (!cmd->error_string
+ && ref_transaction_commit(transaction, &err)) {
+ rp_error("%s", err.buf);
+ strbuf_reset(&err);
+ cmd->error_string = "failed to update ref";
+ }
+ ref_transaction_free(transaction);
+ }
+ strbuf_release(&err);
+}
+
+static void execute_commands_atomic(struct command *commands,
+ struct shallow_info *si)
+{
+ struct command *cmd;
+ struct strbuf err = STRBUF_INIT;
+ const char *reported_error = "atomic push failure";
+
+ transaction = ref_transaction_begin(&err);
+ if (!transaction) {
+ rp_error("%s", err.buf);
+ strbuf_reset(&err);
+ reported_error = "transaction failed to start";
+ goto failure;
+ }
+
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ if (!should_process_cmd(cmd))
+ continue;
+
+ cmd->error_string = update(cmd, si);
+
+ if (cmd->error_string)
+ goto failure;
+ }
+
+ if (ref_transaction_commit(transaction, &err)) {
+ rp_error("%s", err.buf);
+ reported_error = "atomic transaction failed";
+ goto failure;
+ }
+ goto cleanup;
+
+failure:
+ for (cmd = commands; cmd; cmd = cmd->next)
+ if (!cmd->error_string)
+ cmd->error_string = reported_error;
+
+cleanup:
+ ref_transaction_free(transaction);
+ strbuf_release(&err);
+}
+
static void execute_commands(struct command *commands,
const char *unpacker_error,
struct shallow_info *si)
{
- int checked_connectivity;
struct command *cmd;
unsigned char sha1[20];
struct iterate_data data;
@@ -1166,27 +1291,13 @@ static void execute_commands(struct command *commands,
free(head_name_to_free);
head_name = head_name_to_free = resolve_refdup("HEAD", 0, sha1, NULL);
- checked_connectivity = 1;
- for (cmd = commands; cmd; cmd = cmd->next) {
- if (cmd->error_string)
- continue;
-
- if (cmd->skip_update)
- continue;
-
- cmd->error_string = update(cmd, si);
- if (shallow_update && !cmd->error_string &&
- si->shallow_ref[cmd->index]) {
- error("BUG: connectivity check has not been run on ref %s",
- cmd->ref_name);
- checked_connectivity = 0;
- }
- }
+ if (use_atomic)
+ execute_commands_atomic(commands, si);
+ else
+ execute_commands_non_atomic(commands, si);
- if (shallow_update && !checked_connectivity)
- error("BUG: run 'git fsck' for safety.\n"
- "If there are errors, try to remove "
- "the reported refs above");
+ if (shallow_update)
+ warn_if_skipped_connectivity_check(commands, si);
}
static struct command **queue_command(struct command **tail,
@@ -1268,6 +1379,9 @@ static struct command *read_head_info(struct sha1_array *shallow)
use_sideband = LARGE_PACKET_MAX;
if (parse_feature_request(feature_list, "quiet"))
quiet = 1;
+ if (advertise_atomic_push
+ && parse_feature_request(feature_list, "atomic"))
+ use_atomic = 1;
}
if (!strcmp(line, "push-cert")) {
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2d85d260ca..49c64f96d8 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -22,18 +22,13 @@ static unsigned long default_reflog_expire_unreachable;
struct cmd_reflog_expire_cb {
struct rev_info revs;
- int dry_run;
int stalefix;
- int rewrite;
- int updateref;
- int verbose;
unsigned long expire_total;
unsigned long expire_unreachable;
int recno;
};
-struct expire_reflog_cb {
- FILE *newlog;
+struct expire_reflog_policy_cb {
enum {
UE_NORMAL,
UE_ALWAYS,
@@ -41,14 +36,16 @@ struct expire_reflog_cb {
} unreachable_expire_kind;
struct commit_list *mark_list;
unsigned long mark_limit;
- struct cmd_reflog_expire_cb *cmd;
- unsigned char last_kept_sha1[20];
+ struct cmd_reflog_expire_cb cmd;
+ struct commit *tip_commit;
+ struct commit_list *tips;
};
struct collected_reflog {
unsigned char sha1[20];
char reflog[FLEX_ARRAY];
};
+
struct collect_reflog_cb {
struct collected_reflog **e;
int alloc;
@@ -220,7 +217,7 @@ static int keep_entry(struct commit **it, unsigned char *sha1)
* the expire_limit and queue them back, so that the caller can call
* us again to restart the traversal with longer expire_limit.
*/
-static void mark_reachable(struct expire_reflog_cb *cb)
+static void mark_reachable(struct expire_reflog_policy_cb *cb)
{
struct commit *commit;
struct commit_list *pending;
@@ -259,7 +256,7 @@ static void mark_reachable(struct expire_reflog_cb *cb)
cb->mark_list = leftover;
}
-static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsigned char *sha1)
+static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, unsigned char *sha1)
{
/*
* We may or may not have the commit yet - if not, look it
@@ -288,55 +285,39 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
return !(commit->object.flags & REACHABLE);
}
-static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
- const char *email, unsigned long timestamp, int tz,
- const char *message, void *cb_data)
+/*
+ * Return true iff the specified reflog entry should be expired.
+ */
+static int should_expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
{
- struct expire_reflog_cb *cb = cb_data;
+ struct expire_reflog_policy_cb *cb = cb_data;
struct commit *old, *new;
- if (timestamp < cb->cmd->expire_total)
- goto prune;
-
- if (cb->cmd->rewrite)
- osha1 = cb->last_kept_sha1;
+ if (timestamp < cb->cmd.expire_total)
+ return 1;
old = new = NULL;
- if (cb->cmd->stalefix &&
+ if (cb->cmd.stalefix &&
(!keep_entry(&old, osha1) || !keep_entry(&new, nsha1)))
- goto prune;
+ return 1;
- if (timestamp < cb->cmd->expire_unreachable) {
+ if (timestamp < cb->cmd.expire_unreachable) {
if (cb->unreachable_expire_kind == UE_ALWAYS)
- goto prune;
+ return 1;
if (unreachable(cb, old, osha1) || unreachable(cb, new, nsha1))
- goto prune;
+ return 1;
}
- if (cb->cmd->recno && --(cb->cmd->recno) == 0)
- goto prune;
-
- if (cb->newlog) {
- char sign = (tz < 0) ? '-' : '+';
- int zone = (tz < 0) ? (-tz) : tz;
- fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
- sha1_to_hex(osha1), sha1_to_hex(nsha1),
- email, timestamp, sign, zone,
- message);
- hashcpy(cb->last_kept_sha1, nsha1);
- }
- if (cb->cmd->verbose)
- printf("keep %s", message);
- return 0;
- prune:
- if (!cb->newlog)
- printf("would prune %s", message);
- else if (cb->cmd->verbose)
- printf("prune %s", message);
+ if (cb->cmd.recno && --(cb->cmd.recno) == 0)
+ return 1;
+
return 0;
}
-static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
+static int push_tip_to_list(const char *refname, const unsigned char *sha1,
+ int flags, void *cb_data)
{
struct commit_list **list = cb_data;
struct commit *tip_commit;
@@ -349,104 +330,56 @@ static int push_tip_to_list(const char *refname, const unsigned char *sha1, int
return 0;
}
-static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+static void reflog_expiry_prepare(const char *refname,
+ const unsigned char *sha1,
+ void *cb_data)
{
- struct cmd_reflog_expire_cb *cmd = cb_data;
- struct expire_reflog_cb cb;
- struct ref_lock *lock;
- char *log_file, *newlog_path = NULL;
- struct commit *tip_commit;
- struct commit_list *tips;
- int status = 0;
-
- memset(&cb, 0, sizeof(cb));
-
- /*
- * we take the lock for the ref itself to prevent it from
- * getting updated.
- */
- lock = lock_any_ref_for_update(ref, sha1, 0, NULL);
- if (!lock)
- return error("cannot lock ref '%s'", ref);
- log_file = git_pathdup("logs/%s", ref);
- if (!reflog_exists(ref))
- goto finish;
- if (!cmd->dry_run) {
- newlog_path = git_pathdup("logs/%s.lock", ref);
- cb.newlog = fopen(newlog_path, "w");
- }
-
- cb.cmd = cmd;
+ struct expire_reflog_policy_cb *cb = cb_data;
- if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
- tip_commit = NULL;
- cb.unreachable_expire_kind = UE_HEAD;
+ if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
+ cb->tip_commit = NULL;
+ cb->unreachable_expire_kind = UE_HEAD;
} else {
- tip_commit = lookup_commit_reference_gently(sha1, 1);
- if (!tip_commit)
- cb.unreachable_expire_kind = UE_ALWAYS;
+ cb->tip_commit = lookup_commit_reference_gently(sha1, 1);
+ if (!cb->tip_commit)
+ cb->unreachable_expire_kind = UE_ALWAYS;
else
- cb.unreachable_expire_kind = UE_NORMAL;
+ cb->unreachable_expire_kind = UE_NORMAL;
}
- if (cmd->expire_unreachable <= cmd->expire_total)
- cb.unreachable_expire_kind = UE_ALWAYS;
+ if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
+ cb->unreachable_expire_kind = UE_ALWAYS;
- cb.mark_list = NULL;
- tips = NULL;
- if (cb.unreachable_expire_kind != UE_ALWAYS) {
- if (cb.unreachable_expire_kind == UE_HEAD) {
+ cb->mark_list = NULL;
+ cb->tips = NULL;
+ if (cb->unreachable_expire_kind != UE_ALWAYS) {
+ if (cb->unreachable_expire_kind == UE_HEAD) {
struct commit_list *elem;
- for_each_ref(push_tip_to_list, &tips);
- for (elem = tips; elem; elem = elem->next)
- commit_list_insert(elem->item, &cb.mark_list);
+ for_each_ref(push_tip_to_list, &cb->tips);
+ for (elem = cb->tips; elem; elem = elem->next)
+ commit_list_insert(elem->item, &cb->mark_list);
} else {
- commit_list_insert(tip_commit, &cb.mark_list);
+ commit_list_insert(cb->tip_commit, &cb->mark_list);
}
- cb.mark_limit = cmd->expire_total;
- mark_reachable(&cb);
+ cb->mark_limit = cb->cmd.expire_total;
+ mark_reachable(cb);
}
+}
- for_each_reflog_ent(ref, expire_reflog_ent, &cb);
+static void reflog_expiry_cleanup(void *cb_data)
+{
+ struct expire_reflog_policy_cb *cb = cb_data;
- if (cb.unreachable_expire_kind != UE_ALWAYS) {
- if (cb.unreachable_expire_kind == UE_HEAD) {
+ if (cb->unreachable_expire_kind != UE_ALWAYS) {
+ if (cb->unreachable_expire_kind == UE_HEAD) {
struct commit_list *elem;
- for (elem = tips; elem; elem = elem->next)
+ for (elem = cb->tips; elem; elem = elem->next)
clear_commit_marks(elem->item, REACHABLE);
- free_commit_list(tips);
+ free_commit_list(cb->tips);
} else {
- clear_commit_marks(tip_commit, REACHABLE);
+ clear_commit_marks(cb->tip_commit, REACHABLE);
}
}
- finish:
- if (cb.newlog) {
- if (fclose(cb.newlog)) {
- status |= error("%s: %s", strerror(errno),
- newlog_path);
- unlink(newlog_path);
- } else if (cmd->updateref &&
- (write_in_full(lock->lock_fd,
- sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
- write_str_in_full(lock->lock_fd, "\n") != 1 ||
- close_ref(lock) < 0)) {
- status |= error("Couldn't write %s",
- lock->lk->filename.buf);
- unlink(newlog_path);
- } else if (rename(newlog_path, log_file)) {
- status |= error("cannot rename %s to %s",
- newlog_path, log_file);
- unlink(newlog_path);
- } else if (cmd->updateref && commit_ref(lock)) {
- status |= error("Couldn't set %s", lock->ref_name);
- } else {
- adjust_shared_perm(log_file);
- }
- }
- free(newlog_path);
- free(log_file);
- unlock_ref(lock);
- return status;
}
static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
@@ -590,10 +523,11 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
{
- struct cmd_reflog_expire_cb cb;
+ struct expire_reflog_policy_cb cb;
unsigned long now = time(NULL);
int i, status, do_all;
int explicit_expiry = 0;
+ unsigned int flags = 0;
default_reflog_expire_unreachable = now - 30 * 24 * 3600;
default_reflog_expire = now - 90 * 24 * 3600;
@@ -603,33 +537,33 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
do_all = status = 0;
memset(&cb, 0, sizeof(cb));
- cb.expire_total = default_reflog_expire;
- cb.expire_unreachable = default_reflog_expire_unreachable;
+ cb.cmd.expire_total = default_reflog_expire;
+ cb.cmd.expire_unreachable = default_reflog_expire_unreachable;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
- cb.dry_run = 1;
+ flags |= EXPIRE_REFLOGS_DRY_RUN;
else if (starts_with(arg, "--expire=")) {
- if (parse_expiry_date(arg + 9, &cb.expire_total))
+ if (parse_expiry_date(arg + 9, &cb.cmd.expire_total))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_TOTAL;
}
else if (starts_with(arg, "--expire-unreachable=")) {
- if (parse_expiry_date(arg + 21, &cb.expire_unreachable))
+ if (parse_expiry_date(arg + 21, &cb.cmd.expire_unreachable))
die(_("'%s' is not a valid timestamp"), arg);
explicit_expiry |= EXPIRE_UNREACH;
}
else if (!strcmp(arg, "--stale-fix"))
- cb.stalefix = 1;
+ cb.cmd.stalefix = 1;
else if (!strcmp(arg, "--rewrite"))
- cb.rewrite = 1;
+ flags |= EXPIRE_REFLOGS_REWRITE;
else if (!strcmp(arg, "--updateref"))
- cb.updateref = 1;
+ flags |= EXPIRE_REFLOGS_UPDATE_REF;
else if (!strcmp(arg, "--all"))
do_all = 1;
else if (!strcmp(arg, "--verbose"))
- cb.verbose = 1;
+ flags |= EXPIRE_REFLOGS_VERBOSE;
else if (!strcmp(arg, "--")) {
i++;
break;
@@ -645,12 +579,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
* even in older repository. We cannot trust what's reachable
* from reflog if the repository was pruned with older git.
*/
- if (cb.stalefix) {
- init_revisions(&cb.revs, prefix);
- if (cb.verbose)
+ if (cb.cmd.stalefix) {
+ init_revisions(&cb.cmd.revs, prefix);
+ if (flags & EXPIRE_REFLOGS_VERBOSE)
printf("Marking reachable objects...");
- mark_reachable_objects(&cb.revs, 0, 0, NULL);
- if (cb.verbose)
+ mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
+ if (flags & EXPIRE_REFLOGS_VERBOSE)
putchar('\n');
}
@@ -662,8 +596,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
for_each_reflog(collect_reflog, &collected);
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
- set_reflog_expiry_param(&cb, explicit_expiry, e->reflog);
- status |= expire_reflog(e->reflog, e->sha1, 0, &cb);
+ set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
+ status |= reflog_expire(e->reflog, e->sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
free(e);
}
free(collected.e);
@@ -676,8 +614,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
status |= error("%s points nowhere!", argv[i]);
continue;
}
- set_reflog_expiry_param(&cb, explicit_expiry, ref);
- status |= expire_reflog(ref, sha1, 0, &cb);
+ set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
+ status |= reflog_expire(ref, sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
}
return status;
}
@@ -686,29 +628,30 @@ static int count_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
- struct cmd_reflog_expire_cb *cb = cb_data;
- if (!cb->expire_total || timestamp < cb->expire_total)
- cb->recno++;
+ struct expire_reflog_policy_cb *cb = cb_data;
+ if (!cb->cmd.expire_total || timestamp < cb->cmd.expire_total)
+ cb->cmd.recno++;
return 0;
}
static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
{
- struct cmd_reflog_expire_cb cb;
+ struct expire_reflog_policy_cb cb;
int i, status = 0;
+ unsigned int flags = 0;
memset(&cb, 0, sizeof(cb));
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
- cb.dry_run = 1;
+ flags |= EXPIRE_REFLOGS_DRY_RUN;
else if (!strcmp(arg, "--rewrite"))
- cb.rewrite = 1;
+ flags |= EXPIRE_REFLOGS_REWRITE;
else if (!strcmp(arg, "--updateref"))
- cb.updateref = 1;
+ flags |= EXPIRE_REFLOGS_UPDATE_REF;
else if (!strcmp(arg, "--verbose"))
- cb.verbose = 1;
+ flags |= EXPIRE_REFLOGS_VERBOSE;
else if (!strcmp(arg, "--")) {
i++;
break;
@@ -740,15 +683,19 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
recno = strtoul(spec + 2, &ep, 10);
if (*ep == '}') {
- cb.recno = -recno;
+ cb.cmd.recno = -recno;
for_each_reflog_ent(ref, count_reflog_ent, &cb);
} else {
- cb.expire_total = approxidate(spec + 2);
+ cb.cmd.expire_total = approxidate(spec + 2);
for_each_reflog_ent(ref, count_reflog_ent, &cb);
- cb.expire_total = 0;
+ cb.cmd.expire_total = 0;
}
- status |= expire_reflog(ref, sha1, 0, &cb);
+ status |= reflog_expire(ref, sha1, flags,
+ reflog_expiry_prepare,
+ should_expire_reflog_ent,
+ reflog_expiry_cleanup,
+ &cb);
free(ref);
}
return status;
diff --git a/builtin/remote.c b/builtin/remote.c
index b4ff468977..5d3ab906bc 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -10,10 +10,10 @@
static const char * const builtin_remote_usage[] = {
N_("git remote [-v | --verbose]"),
- N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+ N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
N_("git remote rename <old> <new>"),
N_("git remote remove <name>"),
- N_("git remote set-head <name> (-a | --auto | -d | --delete |<branch>)"),
+ N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
N_("git remote [-v | --verbose] show [-n] <name>"),
N_("git remote prune [-n | --dry-run] <name>"),
N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
diff --git a/builtin/repack.c b/builtin/repack.c
index 3f852f35d1..28fbc7099a 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -14,7 +14,7 @@ static int write_bitmaps;
static char *packdir, *packtmp;
static const char *const git_repack_usage[] = {
- N_("git repack [options]"),
+ N_("git repack [<options>]"),
NULL
};
diff --git a/builtin/replace.c b/builtin/replace.c
index 85d39b58d8..54bf01acb4 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -172,7 +172,7 @@ static int replace_object_sha1(const char *object_ref,
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref, repl, prev,
- 0, 1, NULL, &err) ||
+ 0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 98eb8c5404..7afadd2ead 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -9,7 +9,7 @@
#include "pathspec.h"
static const char * const rerere_usage[] = {
- N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
+ N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),
NULL,
};
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 95328b80d9..3626c61da6 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -358,7 +358,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
{
static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
- N_("git rev-parse --parseopt [options] -- [<args>...]"),
+ N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
NULL
};
static struct option parseopt_opts[] = {
@@ -496,9 +496,9 @@ static void die_no_single_rev(int quiet)
}
static const char builtin_rev_parse_usage[] =
-N_("git rev-parse --parseopt [options] -- [<args>...]\n"
+N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
- " or: git rev-parse [options] [<arg>...]\n"
+ " or: git rev-parse [<options>] [<arg>...]\n"
"\n"
"Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
diff --git a/builtin/revert.c b/builtin/revert.c
index f9ed5bd5d0..56a2c36669 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -19,13 +19,13 @@
*/
static const char * const revert_usage[] = {
- N_("git revert [options] <commit-ish>..."),
+ N_("git revert [<options>] <commit-ish>..."),
N_("git revert <subcommand>"),
NULL
};
static const char * const cherry_pick_usage[] = {
- N_("git cherry-pick [options] <commit-ish>..."),
+ N_("git cherry-pick [<options>] <commit-ish>..."),
N_("git cherry-pick <subcommand>"),
NULL
};
diff --git a/builtin/rm.c b/builtin/rm.c
index d8a9c86dd1..3304bff42a 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -14,7 +14,7 @@
#include "pathspec.h"
static const char * const builtin_rm_usage[] = {
- N_("git rm [options] [--] <file>..."),
+ N_("git rm [<options>] [--] <file>..."),
NULL
};
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index b564a77845..b961e5ae78 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -13,7 +13,7 @@
#include "sha1-array.h"
static const char send_pack_usage[] =
-"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
+"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [--atomic] [<host>:]<directory> [<ref>...]\n"
" --all and explicit <ref> specification are mutually exclusive.";
static struct send_pack_args args;
@@ -170,6 +170,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
args.use_thin_pack = 1;
continue;
}
+ if (!strcmp(arg, "--atomic")) {
+ args.atomic = 1;
+ continue;
+ }
if (!strcmp(arg, "--stateless-rpc")) {
args.stateless_rpc = 1;
continue;
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 4b7e53623f..c0bab6aaa9 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static char const * const shortlog_usage[] = {
- N_("git shortlog [<options>] [<revision range>] [[--] [<path>...]]"),
+ N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
NULL
};
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 365228aa8d..f3fb5fb2bf 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -6,11 +6,11 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
- N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n"
+ N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
" [--current] [--color[=<when>] | --no-color] [--sparse]\n"
" [--more=<n> | --list | --independent | --merge-base]\n"
" [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
- N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
+ N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 5ba1f30838..afb10309d6 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -7,7 +7,7 @@
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+ N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"),
N_("git show-ref --exclude-existing[=pattern] < ref-list"),
NULL
};
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index 29fb3f1c20..ce0fde705c 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -4,8 +4,8 @@
#include "parse-options.h"
static const char * const git_symbolic_ref_usage[] = {
- N_("git symbolic-ref [options] name [ref]"),
- N_("git symbolic-ref -d [-q] name"),
+ N_("git symbolic-ref [<options>] <name> [<ref>]"),
+ N_("git symbolic-ref -d [-q] <name>"),
NULL
};
diff --git a/builtin/tag.c b/builtin/tag.c
index e633f4efdb..4194b9a711 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -19,9 +19,9 @@
#include "column.h"
static const char * const git_tag_usage[] = {
- N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+ N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"),
N_("git tag -d <tagname>..."),
- N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+ N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]"
"\n\t\t[<pattern>...]"),
N_("git tag -v <tagname>..."),
NULL
@@ -733,7 +733,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf, object, prev,
- 0, 1, NULL, &err) ||
+ 0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index b0e3dc9105..587898624c 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -400,7 +400,7 @@ static void read_index_info(int line_termination)
}
static const char * const update_index_usage[] = {
- N_("git update-index [options] [--] [<file>...]"),
+ N_("git update-index [<options>] [--] [<file>...]"),
NULL
};
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 1993529521..3d79a46b03 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -6,9 +6,9 @@
#include "argv-array.h"
static const char * const git_update_ref_usage[] = {
- N_("git update-ref [options] -d <refname> [<oldval>]"),
- N_("git update-ref [options] <refname> <newval> [<oldval>]"),
- N_("git update-ref [options] --stdin [-z]"),
+ N_("git update-ref [<options>] -d <refname> [<old-val>]"),
+ N_("git update-ref [<options>] <refname> <new-val> [<old-val>]"),
+ N_("git update-ref [<options>] --stdin [-z]"),
NULL
};
@@ -198,8 +198,9 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
if (*next != line_termination)
die("update %s: extra input: %s", refname, next);
- if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
- update_flags, have_old, msg, &err))
+ if (ref_transaction_update(transaction, refname,
+ new_sha1, have_old ? old_sha1 : NULL,
+ update_flags, msg, &err))
die("%s", err.buf);
update_flags = 0;
@@ -264,8 +265,9 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
if (*next != line_termination)
die("delete %s: extra input: %s", refname, next);
- if (ref_transaction_delete(transaction, refname, old_sha1,
- update_flags, have_old, msg, &err))
+ if (ref_transaction_delete(transaction, refname,
+ have_old ? old_sha1 : NULL,
+ update_flags, msg, &err))
die("%s", err.buf);
update_flags = 0;
@@ -280,7 +282,6 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
{
struct strbuf err = STRBUF_INIT;
char *refname;
- unsigned char new_sha1[20];
unsigned char old_sha1[20];
refname = parse_refname(input, &next);
@@ -291,13 +292,11 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
PARSE_SHA1_OLD))
hashclr(old_sha1);
- hashcpy(new_sha1, old_sha1);
-
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
- if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
- update_flags, 1, msg, &err))
+ if (ref_transaction_verify(transaction, refname, old_sha1,
+ update_flags, &err))
die("%s", err.buf);
update_flags = 0;
@@ -353,7 +352,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
{
const char *refname, *oldval;
unsigned char sha1[20], oldsha1[20];
- int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
+ int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
+ unsigned int flags = 0;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
index b0f85042b2..ec0c4e3d83 100644
--- a/builtin/verify-commit.c
+++ b/builtin/verify-commit.c
@@ -14,7 +14,7 @@
#include "gpg-interface.h"
static const char * const verify_commit_usage[] = {
- N_("git verify-commit [-v|--verbose] <commit>..."),
+ N_("git verify-commit [-v | --verbose] <commit>..."),
NULL
};
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
index 7747537beb..c94e156932 100644
--- a/builtin/verify-pack.c
+++ b/builtin/verify-pack.c
@@ -51,7 +51,7 @@ static int verify_one_pack(const char *path, unsigned int flags)
}
static const char * const verify_pack_usage[] = {
- N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
+ N_("git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."),
NULL
};
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
index 9cdf332333..53c68fce3a 100644
--- a/builtin/verify-tag.c
+++ b/builtin/verify-tag.c
@@ -14,7 +14,7 @@
#include "gpg-interface.h"
static const char * const verify_tag_usage[] = {
- N_("git verify-tag [-v|--verbose] <tag>..."),
+ N_("git verify-tag [-v | --verbose] <tag>..."),
NULL
};