From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Subject: [PATCH 3/3] format-patch: --no-clobber refrains from overwriting output files
Date: Fri, 22 Feb 2019 12:11:11 -0800 [thread overview]
Message-ID: <20190222201111.98196-4-gitster@pobox.com> (raw)
In-Reply-To: <20190222201111.98196-1-gitster@pobox.com>
If you keep an output for an older iteration of the same topic in
the same directory around and use "git format-patch" to prepare a
newer iteration of the topic, those commits that happen to be at the
same position in the series that have not been retitled will get the
same filename---and the command opens them for writing without any
check.
Existing "-o outdir" and "-v number" options are both good ways to
avoid such name collisions, and in general helps to give good ways
to compare the latest iteration with older iteration(s), but let's
see if "--no-clobber" option that forbids overwrting existing files
would also help people.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Documentation/git-format-patch.txt | 8 +++++++-
builtin/log.c | 32 ++++++++++++++++++++++++------
t/t4014-format-patch.sh | 16 +++++++++++++++
3 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 1af85d404f..540822b3b4 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -25,7 +25,7 @@ SYNOPSIS
[--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
[--interdiff=<previous>]
[--range-diff=<previous> [--creation-factor=<percent>]]
- [--progress]
+ [--progress] [--[no-]clobber]
[<common diff options>]
[ <since> | <revision range> ]
@@ -93,6 +93,12 @@ include::diff-options.txt[]
Use <dir> to store the resulting files, instead of the
current working directory.
+--clobber::
+--no-clobber::
+ (experimental)
+ Allow overwriting existing files, which is the default. To
+ make the command refrain from overwriting, use `--no-clobber`.
+
-n::
--numbered::
Name output in '[PATCH n/m]' format, even with a single patch.
diff --git a/builtin/log.c b/builtin/log.c
index ca86611efe..7421f1cc93 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -867,8 +867,16 @@ static int git_format_config(const char *var, const char *value, void *cb)
static const char *output_directory = NULL;
static int outdir_offset;
+static FILE *fopen_excl(const char *filename)
+{
+ int fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ if (fd < 0)
+ return NULL;
+ return fdopen(fd, "w");
+}
+
static int open_next_file(struct commit *commit, const char *subject,
- struct rev_info *rev, int quiet)
+ struct rev_info *rev, int quiet, int clobber)
{
struct strbuf filename = STRBUF_INIT;
int suffix_len = strlen(rev->patch_suffix) + 1;
@@ -893,7 +901,12 @@ static int open_next_file(struct commit *commit, const char *subject,
if (!quiet)
printf("%s\n", filename.buf + outdir_offset);
- if ((rev->diffopt.file = fopen(filename.buf, "w")) == NULL) {
+ if (clobber)
+ rev->diffopt.file = fopen(filename.buf, "w");
+ else
+ rev->diffopt.file = fopen_excl(filename.buf);
+
+ if (!rev->diffopt.file) {
error_errno(_("cannot open patch file %s"), filename.buf);
strbuf_release(&filename);
return -1;
@@ -1030,7 +1043,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
struct commit *origin,
int nr, struct commit **list,
const char *branch_name,
- int quiet)
+ int quiet,
+ int clobber)
{
const char *committer;
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
@@ -1049,7 +1063,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
committer = git_committer_info(0);
if (!use_stdout &&
- open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
+ open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter",
+ rev, quiet, clobber))
die(_("failed to create cover-letter file"));
log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
@@ -1509,6 +1524,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf buf = STRBUF_INIT;
int use_patch_format = 0;
int quiet = 0;
+ int clobber = 1;
int reroll_count = -1;
char *branch_name = NULL;
char *base_commit = NULL;
@@ -1595,6 +1611,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_BOOL(0, "progress", &show_progress,
N_("show progress while generating patches")),
+ OPT_BOOL(0, "clobber", &clobber,
+ N_("allow overwriting output files")),
OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
N_("show changes against <rev> in cover letter or single patch"),
parse_opt_object_name),
@@ -1885,7 +1903,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (thread)
gen_message_id(&rev, "cover");
make_cover_letter(&rev, use_stdout,
- origin, nr, list, branch_name, quiet);
+ origin, nr, list, branch_name,
+ quiet, clobber);
print_bases(&bases, rev.diffopt.file);
print_signature(rev.diffopt.file);
total++;
@@ -1940,7 +1959,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
if (!use_stdout &&
- open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
+ open_next_file(rev.numbered_files ? NULL : commit, NULL,
+ &rev, quiet, clobber))
die(_("failed to create output files"));
shown = log_tree_commit(&rev, commit);
free_commit_buffer(the_repository->parsed_objects,
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index b6e2fdbc44..384a1fd9e7 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -595,6 +595,22 @@ test_expect_success 'failure to write cover-letter aborts gracefully' '
test_must_fail git format-patch --no-renames --cover-letter -1
'
+test_expect_success 'refrain from overwriting a patch with --no-clobber' '
+ rm -f 000[01]-*.patch &&
+ git format-patch --no-clobber --no-renames --cover-letter -1 >filelist &&
+ # empty the files output by the command ...
+ for f in $(cat filelist)
+ do
+ : >"$f" || return 1
+ done &&
+ test_must_fail git format-patch --no-clobber --cover-letter --no-renames -1 &&
+ # ... and make sure they stay empty
+ for f in $(cat filelist)
+ do
+ ! test -s "$f" || return 1
+ done
+'
+
test_expect_success 'cover-letter inherits diff options' '
git mv file foo &&
git commit -m foo &&
--
2.21.0-rc2
next prev parent reply other threads:[~2019-02-22 20:11 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-02-22 20:11 [PATCH 0/3] format-patch --no-clobber Junio C Hamano
2019-02-22 20:11 ` [PATCH 1/3] builtin/log: downcase the beginning of error messages Junio C Hamano
2019-02-22 20:24 ` Eric Sunshine
2019-02-22 20:40 ` Junio C Hamano
2019-02-22 20:11 ` [PATCH 2/3] format-patch: notice failure to open cover letter for writing Junio C Hamano
2019-02-22 20:11 ` Junio C Hamano [this message]
2019-02-22 20:38 ` [PATCH 3/3] format-patch: --no-clobber refrains from overwriting output files Eric Sunshine
2019-02-23 13:34 ` Jeff King
2019-03-12 20:53 ` Ntentos Stavros
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190222201111.98196-4-gitster@pobox.com \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).