2015-08-04 15:51:24 +02:00
|
|
|
/*
|
|
|
|
* Builtin "git am"
|
|
|
|
*
|
|
|
|
* Based on git-am.sh by Junio C Hamano.
|
|
|
|
*/
|
2019-01-24 09:29:12 +01:00
|
|
|
#define USE_THE_INDEX_COMPATIBILITY_MACROS
|
2015-08-04 15:51:24 +02:00
|
|
|
#include "cache.h"
|
2017-06-14 20:07:36 +02:00
|
|
|
#include "config.h"
|
2015-08-04 15:51:24 +02:00
|
|
|
#include "builtin.h"
|
2018-04-10 23:26:18 +02:00
|
|
|
#include "exec-cmd.h"
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
#include "parse-options.h"
|
|
|
|
#include "dir.h"
|
2015-08-04 15:51:26 +02:00
|
|
|
#include "run-command.h"
|
2015-08-04 15:51:28 +02:00
|
|
|
#include "quote.h"
|
2015-08-25 23:57:09 +02:00
|
|
|
#include "tempfile.h"
|
2015-08-04 15:51:29 +02:00
|
|
|
#include "lockfile.h"
|
2015-08-04 15:51:30 +02:00
|
|
|
#include "cache-tree.h"
|
|
|
|
#include "refs.h"
|
|
|
|
#include "commit.h"
|
2015-08-04 15:51:31 +02:00
|
|
|
#include "diff.h"
|
|
|
|
#include "diffcore.h"
|
2015-08-04 15:51:34 +02:00
|
|
|
#include "unpack-trees.h"
|
|
|
|
#include "branch.h"
|
2015-08-04 15:51:39 +02:00
|
|
|
#include "sequencer.h"
|
2015-08-04 15:51:41 +02:00
|
|
|
#include "revision.h"
|
|
|
|
#include "merge-recursive.h"
|
2015-08-04 15:51:43 +02:00
|
|
|
#include "log-tree.h"
|
2015-08-04 15:51:55 +02:00
|
|
|
#include "notes-utils.h"
|
builtin-am: rerere support
git-am.sh will call git-rerere at the following events:
* "git rerere" when a three-way merge fails to record the conflicted
automerge results. Since 8389b52 (git-rerere: reuse recorded resolve.,
2006-01-28)
* Since cb6020b (Teach --[no-]rerere-autoupdate option to merge,
revert and friends, 2009-12-04), git-am.sh supports the
--[no-]rerere-autoupdate option as well, and would pass it to
git-rerere.
* "git rerere" when --resolved, to record the hand resolution. Since
f131dd4 (rerere: record (or avoid misrecording) resolved, skipped or
aborted rebase/am, 2006-12-08)
* "git rerere clear" when --skip-ing. Since f131dd4 (rerere: record (or
avoid misrecording) resolved, skipped or aborted rebase/am,
2006-12-08)
* "git rerere clear" when --abort-ing. Since 3e5057a (git am --abort,
2008-07-16)
Re-implement the above in builtin/am.c.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:59 +02:00
|
|
|
#include "rerere.h"
|
2015-08-04 15:52:03 +02:00
|
|
|
#include "prompt.h"
|
2015-10-15 02:45:43 +02:00
|
|
|
#include "mailinfo.h"
|
2016-09-04 22:18:33 +02:00
|
|
|
#include "apply.h"
|
2016-08-30 21:36:42 +02:00
|
|
|
#include "string-list.h"
|
2017-08-19 00:20:21 +02:00
|
|
|
#include "packfile.h"
|
2018-06-29 03:21:56 +02:00
|
|
|
#include "repository.h"
|
2015-08-04 15:51:28 +02:00
|
|
|
|
2015-08-04 15:51:29 +02:00
|
|
|
/**
|
|
|
|
* Returns the length of the first line of msg.
|
|
|
|
*/
|
|
|
|
static int linelen(const char *msg)
|
|
|
|
{
|
|
|
|
return strchrnul(msg, '\n') - msg;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:52:00 +02:00
|
|
|
/**
|
|
|
|
* Returns true if `str` consists of only whitespace, false otherwise.
|
|
|
|
*/
|
|
|
|
static int str_isspace(const char *str)
|
|
|
|
{
|
|
|
|
for (; *str; str++)
|
|
|
|
if (!isspace(*str))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:26 +02:00
|
|
|
enum patch_format {
|
|
|
|
PATCH_FORMAT_UNKNOWN = 0,
|
2015-08-04 15:52:00 +02:00
|
|
|
PATCH_FORMAT_MBOX,
|
2015-08-04 15:52:01 +02:00
|
|
|
PATCH_FORMAT_STGIT,
|
2015-08-04 15:52:02 +02:00
|
|
|
PATCH_FORMAT_STGIT_SERIES,
|
2016-06-05 06:46:41 +02:00
|
|
|
PATCH_FORMAT_HG,
|
|
|
|
PATCH_FORMAT_MBOXRD
|
2015-08-04 15:51:26 +02:00
|
|
|
};
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
|
2015-08-04 15:51:46 +02:00
|
|
|
enum keep_type {
|
|
|
|
KEEP_FALSE = 0,
|
|
|
|
KEEP_TRUE, /* pass -k flag to git-mailinfo */
|
|
|
|
KEEP_NON_PATCH /* pass -b flag to git-mailinfo */
|
|
|
|
};
|
|
|
|
|
2015-08-04 15:51:49 +02:00
|
|
|
enum scissors_type {
|
|
|
|
SCISSORS_UNSET = -1,
|
|
|
|
SCISSORS_FALSE = 0, /* pass --no-scissors to git-mailinfo */
|
|
|
|
SCISSORS_TRUE /* pass --scissors to git-mailinfo */
|
|
|
|
};
|
|
|
|
|
am: let --signoff override --no-signoff
After resolving a conflicting patch, a user may wish to sign off the
patch to declare that the patch has been modified. As such, the user
will expect that running "git am --signoff --continue" will append the
signoff to the commit message.
However, the --signoff option is only taken into account during the
mail-parsing stage. If the --signoff option is set, then the signoff
will be appended to the commit message. Since the mail-parsing stage
comes before the patch application stage, the --signoff option, if
provided on the command-line when resuming, will have no effect at all.
We cannot move the append_signoff() call to the patch application stage
as the applypatch-msg hook and interactive mode, which run before patch
application, may expect the signoff to be there.
Fix this by taking note if the user explictly set the --signoff option
on the command-line, and append the signoff to the commit message when
resuming if so.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 16:08:51 +02:00
|
|
|
enum signoff_type {
|
|
|
|
SIGNOFF_FALSE = 0,
|
|
|
|
SIGNOFF_TRUE = 1,
|
|
|
|
SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
|
|
|
|
};
|
|
|
|
|
am: support --show-current-patch=raw as a synonym for--show-current-patch
When "git am --show-current-patch" was added in commit 984913a210 ("am:
add --show-current-patch", 2018-02-12), "git am" started recommending it
as a replacement for .git/rebase-merge/patch. Unfortunately the suggestion
is somewhat misguided; for example, the output "git am --show-current-patch"
cannot be passed to "git apply" if it is encoded as quoted-printable or
base64. To simplify worktree operations and to avoid that users poke into
.git, it would be better if "git am" also provided a mode that copies
.git/rebase-merge/patch to stdout.
One possibility could be to have completely separate options, introducing
for example --show-current-message (for .git/rebase-apply/NNNN)
and --show-current-diff (for .git/rebase-apply/patch), while possibly
deprecating --show-current-patch.
That would even remove the need for the first two patches in the series.
However, the long common prefix would have prevented using an abbreviated
option such as "--show". Therefore, I chose instead to add a string
argument to --show-current-patch. The new argument is optional, so that
"git am --show-current-patch"'s behavior remains backwards-compatible.
The next choice to make is how to handle multiple --show-current-patch
options. Right now, something like "git am --abort --show-current-patch"
is rejected, and the previous suggestion would likewise have naturally
rejected a command line like
git am --show-current-message --show-current-diff
Therefore, I decided to also reject for example
git am --show-current-patch=diff --show-current-patch=raw
In other words the whole of --show-current-patch=xxx (including the
optional argument) is treated as the command mode. I found this to be
more consistent and intuitive, even though it differs from the usual
"last one wins" semantics of the git command line.
Add the code to parse submodes based on the above design, where for now
"raw" is the only valid submode. "raw" prints the full e-mail message
just like "git am --show-current-patch".
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-20 15:15:18 +01:00
|
|
|
enum show_patch_type {
|
|
|
|
SHOW_PATCH_RAW = 0,
|
2020-02-20 15:15:19 +01:00
|
|
|
SHOW_PATCH_DIFF = 1,
|
am: support --show-current-patch=raw as a synonym for--show-current-patch
When "git am --show-current-patch" was added in commit 984913a210 ("am:
add --show-current-patch", 2018-02-12), "git am" started recommending it
as a replacement for .git/rebase-merge/patch. Unfortunately the suggestion
is somewhat misguided; for example, the output "git am --show-current-patch"
cannot be passed to "git apply" if it is encoded as quoted-printable or
base64. To simplify worktree operations and to avoid that users poke into
.git, it would be better if "git am" also provided a mode that copies
.git/rebase-merge/patch to stdout.
One possibility could be to have completely separate options, introducing
for example --show-current-message (for .git/rebase-apply/NNNN)
and --show-current-diff (for .git/rebase-apply/patch), while possibly
deprecating --show-current-patch.
That would even remove the need for the first two patches in the series.
However, the long common prefix would have prevented using an abbreviated
option such as "--show". Therefore, I chose instead to add a string
argument to --show-current-patch. The new argument is optional, so that
"git am --show-current-patch"'s behavior remains backwards-compatible.
The next choice to make is how to handle multiple --show-current-patch
options. Right now, something like "git am --abort --show-current-patch"
is rejected, and the previous suggestion would likewise have naturally
rejected a command line like
git am --show-current-message --show-current-diff
Therefore, I decided to also reject for example
git am --show-current-patch=diff --show-current-patch=raw
In other words the whole of --show-current-patch=xxx (including the
optional argument) is treated as the command mode. I found this to be
more consistent and intuitive, even though it differs from the usual
"last one wins" semantics of the git command line.
Add the code to parse submodes based on the above design, where for now
"raw" is the only valid submode. "raw" prints the full e-mail message
just like "git am --show-current-patch".
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-02-20 15:15:18 +01:00
|
|
|
};
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
struct am_state {
|
|
|
|
/* state directory path */
|
|
|
|
char *dir;
|
|
|
|
|
|
|
|
/* current and last patch numbers, 1-indexed */
|
|
|
|
int cur;
|
|
|
|
int last;
|
2015-08-04 15:51:26 +02:00
|
|
|
|
2015-08-04 15:51:28 +02:00
|
|
|
/* commit metadata and message */
|
|
|
|
char *author_name;
|
|
|
|
char *author_email;
|
|
|
|
char *author_date;
|
|
|
|
char *msg;
|
|
|
|
size_t msg_len;
|
|
|
|
|
2015-08-04 15:51:54 +02:00
|
|
|
/* when --rebasing, records the original commit the patch came from */
|
2016-09-05 22:08:09 +02:00
|
|
|
struct object_id orig_commit;
|
2015-08-04 15:51:54 +02:00
|
|
|
|
2015-08-04 15:51:26 +02:00
|
|
|
/* number of digits in patch filename */
|
|
|
|
int prec;
|
2015-08-04 15:51:37 +02:00
|
|
|
|
|
|
|
/* various operating modes and command line options */
|
2015-08-04 15:52:03 +02:00
|
|
|
int interactive;
|
2015-08-04 15:51:41 +02:00
|
|
|
int threeway;
|
2015-08-04 15:51:37 +02:00
|
|
|
int quiet;
|
am: let --signoff override --no-signoff
After resolving a conflicting patch, a user may wish to sign off the
patch to declare that the patch has been modified. As such, the user
will expect that running "git am --signoff --continue" will append the
signoff to the commit message.
However, the --signoff option is only taken into account during the
mail-parsing stage. If the --signoff option is set, then the signoff
will be appended to the commit message. Since the mail-parsing stage
comes before the patch application stage, the --signoff option, if
provided on the command-line when resuming, will have no effect at all.
We cannot move the append_signoff() call to the patch application stage
as the applypatch-msg hook and interactive mode, which run before patch
application, may expect the signoff to be there.
Fix this by taking note if the user explictly set the --signoff option
on the command-line, and append the signoff to the commit message when
resuming if so.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 16:08:51 +02:00
|
|
|
int signoff; /* enum signoff_type */
|
2015-08-04 15:51:45 +02:00
|
|
|
int utf8;
|
2015-08-04 15:51:46 +02:00
|
|
|
int keep; /* enum keep_type */
|
2015-08-04 15:51:47 +02:00
|
|
|
int message_id;
|
2015-08-04 15:51:49 +02:00
|
|
|
int scissors; /* enum scissors_type */
|
2021-05-09 19:12:13 +02:00
|
|
|
int quoted_cr; /* enum quoted_cr_action */
|
2020-07-28 22:24:27 +02:00
|
|
|
struct strvec git_apply_opts;
|
2015-08-04 15:51:38 +02:00
|
|
|
const char *resolvemsg;
|
2015-08-04 15:51:52 +02:00
|
|
|
int committer_date_is_author_date;
|
2015-08-04 15:51:51 +02:00
|
|
|
int ignore_date;
|
builtin-am: rerere support
git-am.sh will call git-rerere at the following events:
* "git rerere" when a three-way merge fails to record the conflicted
automerge results. Since 8389b52 (git-rerere: reuse recorded resolve.,
2006-01-28)
* Since cb6020b (Teach --[no-]rerere-autoupdate option to merge,
revert and friends, 2009-12-04), git-am.sh supports the
--[no-]rerere-autoupdate option as well, and would pass it to
git-rerere.
* "git rerere" when --resolved, to record the hand resolution. Since
f131dd4 (rerere: record (or avoid misrecording) resolved, skipped or
aborted rebase/am, 2006-12-08)
* "git rerere clear" when --skip-ing. Since f131dd4 (rerere: record (or
avoid misrecording) resolved, skipped or aborted rebase/am,
2006-12-08)
* "git rerere clear" when --abort-ing. Since 3e5057a (git am --abort,
2008-07-16)
Re-implement the above in builtin/am.c.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:59 +02:00
|
|
|
int allow_rerere_autoupdate;
|
2015-08-04 15:51:53 +02:00
|
|
|
const char *sign_commit;
|
2015-08-04 15:51:42 +02:00
|
|
|
int rebasing;
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2017-04-20 23:09:35 +02:00
|
|
|
* Initializes am_state with the default values.
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
*/
|
2017-04-20 23:09:35 +02:00
|
|
|
static void am_state_init(struct am_state *state)
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
{
|
2015-08-04 15:51:53 +02:00
|
|
|
int gpgsign;
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
memset(state, 0, sizeof(*state));
|
|
|
|
|
2017-04-20 23:09:35 +02:00
|
|
|
state->dir = git_pathdup("rebase-apply");
|
2015-08-04 15:51:26 +02:00
|
|
|
|
|
|
|
state->prec = 4;
|
2015-08-04 15:51:45 +02:00
|
|
|
|
2015-08-04 16:19:26 +02:00
|
|
|
git_config_get_bool("am.threeway", &state->threeway);
|
|
|
|
|
2015-08-04 15:51:45 +02:00
|
|
|
state->utf8 = 1;
|
2015-08-04 15:51:47 +02:00
|
|
|
|
|
|
|
git_config_get_bool("am.messageid", &state->message_id);
|
2015-08-04 15:51:49 +02:00
|
|
|
|
|
|
|
state->scissors = SCISSORS_UNSET;
|
2021-05-09 19:12:13 +02:00
|
|
|
state->quoted_cr = quoted_cr_unset;
|
builtin-am: pass git-apply's options to git-apply
git-am.sh recognizes some of git-apply's options, and would pass them to
git-apply:
* --whitespace, since 8c31cb8 (git-am: --whitespace=x option.,
2006-02-28)
* -C, since 67dad68 (add -C[NUM] to git-am, 2007-02-08)
* -p, since 2092a1f (Teach git-am to pass -p option down to git-apply,
2007-02-11)
* --directory, since b47dfe9 (git-am: add --directory=<dir> option,
2009-01-11)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
* --ignore-space-change, --ignore-whitespace, since 86c91f9 (git apply:
option to ignore whitespace differences, 2009-08-04)
* --exclude, since 77e9e49 (am: pass exclude down to apply, 2011-08-03)
* --include, since 58725ef (am: support --include option, 2012-03-28)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
Re-implement support for these options in builtin/am.c.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:50 +02:00
|
|
|
|
2020-07-28 22:24:27 +02:00
|
|
|
strvec_init(&state->git_apply_opts);
|
2015-08-04 15:51:53 +02:00
|
|
|
|
|
|
|
if (!git_config_get_bool("commit.gpgsign", &gpgsign))
|
|
|
|
state->sign_commit = gpgsign ? "" : NULL;
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Releases memory allocated by an am_state.
|
|
|
|
*/
|
|
|
|
static void am_state_release(struct am_state *state)
|
|
|
|
{
|
|
|
|
free(state->dir);
|
2015-08-04 15:51:28 +02:00
|
|
|
free(state->author_name);
|
|
|
|
free(state->author_email);
|
|
|
|
free(state->author_date);
|
|
|
|
free(state->msg);
|
2020-07-28 22:24:27 +02:00
|
|
|
strvec_clear(&state->git_apply_opts);
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
}
|
|
|
|
|
2021-05-09 19:12:13 +02:00
|
|
|
static int am_option_parse_quoted_cr(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
BUG_ON_OPT_NEG(unset);
|
|
|
|
|
|
|
|
if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
|
|
|
|
return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
/**
|
|
|
|
* Returns path relative to the am_state directory.
|
|
|
|
*/
|
|
|
|
static inline const char *am_path(const struct am_state *state, const char *path)
|
|
|
|
{
|
|
|
|
return mkpath("%s/%s", state->dir, path);
|
|
|
|
}
|
|
|
|
|
2015-08-24 18:12:53 +02:00
|
|
|
/**
|
|
|
|
* For convenience to call write_file()
|
|
|
|
*/
|
2016-07-08 11:08:05 +02:00
|
|
|
static void write_state_text(const struct am_state *state,
|
|
|
|
const char *name, const char *string)
|
2015-08-24 18:12:53 +02:00
|
|
|
{
|
2016-07-08 11:08:05 +02:00
|
|
|
write_file(am_path(state, name), "%s", string);
|
2015-08-24 18:12:53 +02:00
|
|
|
}
|
|
|
|
|
2016-07-08 11:08:05 +02:00
|
|
|
static void write_state_count(const struct am_state *state,
|
|
|
|
const char *name, int value)
|
2015-08-24 18:12:53 +02:00
|
|
|
{
|
2016-07-08 11:08:05 +02:00
|
|
|
write_file(am_path(state, name), "%d", value);
|
2015-08-24 18:12:53 +02:00
|
|
|
}
|
|
|
|
|
2016-07-08 11:08:05 +02:00
|
|
|
static void write_state_bool(const struct am_state *state,
|
|
|
|
const char *name, int value)
|
2015-08-24 18:12:53 +02:00
|
|
|
{
|
2016-07-08 11:08:05 +02:00
|
|
|
write_state_text(state, name, value ? "t" : "f");
|
2015-08-24 18:12:53 +02:00
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:37 +02:00
|
|
|
/**
|
|
|
|
* If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline
|
|
|
|
* at the end.
|
|
|
|
*/
|
2021-07-13 10:05:18 +02:00
|
|
|
__attribute__((format (printf, 3, 4)))
|
2015-08-04 15:51:37 +02:00
|
|
|
static void say(const struct am_state *state, FILE *fp, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
if (!state->quiet) {
|
|
|
|
vfprintf(fp, fmt, ap);
|
|
|
|
putc('\n', fp);
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
/**
|
|
|
|
* Returns 1 if there is an am session in progress, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int am_in_progress(const struct am_state *state)
|
|
|
|
{
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (lstat(state->dir, &st) < 0 || !S_ISDIR(st.st_mode))
|
|
|
|
return 0;
|
|
|
|
if (lstat(am_path(state, "last"), &st) || !S_ISREG(st.st_mode))
|
|
|
|
return 0;
|
|
|
|
if (lstat(am_path(state, "next"), &st) || !S_ISREG(st.st_mode))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads the contents of `file` in the `state` directory into `sb`. Returns the
|
|
|
|
* number of bytes read on success, -1 if the file does not exist. If `trim` is
|
|
|
|
* set, trailing whitespace will be removed.
|
|
|
|
*/
|
|
|
|
static int read_state_file(struct strbuf *sb, const struct am_state *state,
|
|
|
|
const char *file, int trim)
|
|
|
|
{
|
|
|
|
strbuf_reset(sb);
|
|
|
|
|
|
|
|
if (strbuf_read_file(sb, am_path(state, file), 0) >= 0) {
|
|
|
|
if (trim)
|
|
|
|
strbuf_trim(sb);
|
|
|
|
|
|
|
|
return sb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
die_errno(_("could not read '%s'"), am_path(state, file));
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:28 +02:00
|
|
|
/**
|
|
|
|
* Reads and parses the state directory's "author-script" file, and sets
|
|
|
|
* state->author_name, state->author_email and state->author_date accordingly.
|
|
|
|
* Returns 0 on success, -1 if the file could not be parsed.
|
|
|
|
*
|
|
|
|
* The author script is of the format:
|
|
|
|
*
|
|
|
|
* GIT_AUTHOR_NAME='$author_name'
|
|
|
|
* GIT_AUTHOR_EMAIL='$author_email'
|
|
|
|
* GIT_AUTHOR_DATE='$author_date'
|
|
|
|
*
|
|
|
|
* where $author_name, $author_email and $author_date are quoted. We are strict
|
|
|
|
* with our parsing, as the file was meant to be eval'd in the old git-am.sh
|
|
|
|
* script, and thus if the file differs from what this function expects, it is
|
|
|
|
* better to bail out than to do something that the user does not expect.
|
|
|
|
*/
|
2018-10-31 11:15:54 +01:00
|
|
|
static int read_am_author_script(struct am_state *state)
|
2015-08-04 15:51:28 +02:00
|
|
|
{
|
|
|
|
const char *filename = am_path(state, "author-script");
|
|
|
|
|
|
|
|
assert(!state->author_name);
|
|
|
|
assert(!state->author_email);
|
|
|
|
assert(!state->author_date);
|
|
|
|
|
2018-10-31 11:15:55 +01:00
|
|
|
return read_author_script(filename, &state->author_name,
|
|
|
|
&state->author_email, &state->author_date, 1);
|
2015-08-04 15:51:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Saves state->author_name, state->author_email and state->author_date in the
|
|
|
|
* state directory's "author-script" file.
|
|
|
|
*/
|
|
|
|
static void write_author_script(const struct am_state *state)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addstr(&sb, "GIT_AUTHOR_NAME=");
|
|
|
|
sq_quote_buf(&sb, state->author_name);
|
|
|
|
strbuf_addch(&sb, '\n');
|
|
|
|
|
|
|
|
strbuf_addstr(&sb, "GIT_AUTHOR_EMAIL=");
|
|
|
|
sq_quote_buf(&sb, state->author_email);
|
|
|
|
strbuf_addch(&sb, '\n');
|
|
|
|
|
|
|
|
strbuf_addstr(&sb, "GIT_AUTHOR_DATE=");
|
|
|
|
sq_quote_buf(&sb, state->author_date);
|
|
|
|
strbuf_addch(&sb, '\n');
|
|
|
|
|
2015-08-24 18:12:53 +02:00
|
|
|
write_state_text(state, "author-script", sb.buf);
|
2015-08-04 15:51:28 +02:00
|
|
|
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads the commit message from the state directory's "final-commit" file,
|
|
|
|
* setting state->msg to its contents and state->msg_len to the length of its
|
|
|
|
* contents in bytes.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 if the file does not exist.
|
|
|
|
*/
|
|
|
|
static int read_commit_msg(struct am_state *state)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
assert(!state->msg);
|
|
|
|
|
|
|
|
if (read_state_file(&sb, state, "final-commit", 0) < 0) {
|
|
|
|
strbuf_release(&sb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->msg = strbuf_detach(&sb, &state->msg_len);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Saves state->msg in the state directory's "final-commit" file.
|
|
|
|
*/
|
|
|
|
static void write_commit_msg(const struct am_state *state)
|
|
|
|
{
|
|
|
|
const char *filename = am_path(state, "final-commit");
|
2016-07-08 11:12:55 +02:00
|
|
|
write_file_buf(filename, state->msg, state->msg_len);
|
2015-08-04 15:51:28 +02:00
|
|
|
}
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
/**
|
|
|
|
* Loads state from disk.
|
|
|
|
*/
|
|
|
|
static void am_load(struct am_state *state)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (read_state_file(&sb, state, "next", 1) < 0)
|
2018-05-02 11:38:39 +02:00
|
|
|
BUG("state file 'next' does not exist");
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
state->cur = strtol(sb.buf, NULL, 10);
|
|
|
|
|
|
|
|
if (read_state_file(&sb, state, "last", 1) < 0)
|
2018-05-02 11:38:39 +02:00
|
|
|
BUG("state file 'last' does not exist");
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
state->last = strtol(sb.buf, NULL, 10);
|
|
|
|
|
2018-10-31 11:15:54 +01:00
|
|
|
if (read_am_author_script(state) < 0)
|
2015-08-04 15:51:28 +02:00
|
|
|
die(_("could not parse author script"));
|
|
|
|
|
|
|
|
read_commit_msg(state);
|
|
|
|
|
2015-08-04 15:51:54 +02:00
|
|
|
if (read_state_file(&sb, state, "original-commit", 1) < 0)
|
2016-09-05 22:08:09 +02:00
|
|
|
oidclr(&state->orig_commit);
|
|
|
|
else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
|
2015-08-04 15:51:54 +02:00
|
|
|
die(_("could not parse %s"), am_path(state, "original-commit"));
|
|
|
|
|
2015-08-04 15:51:41 +02:00
|
|
|
read_state_file(&sb, state, "threeway", 1);
|
|
|
|
state->threeway = !strcmp(sb.buf, "t");
|
|
|
|
|
2015-08-04 15:51:37 +02:00
|
|
|
read_state_file(&sb, state, "quiet", 1);
|
|
|
|
state->quiet = !strcmp(sb.buf, "t");
|
|
|
|
|
2015-08-04 15:51:39 +02:00
|
|
|
read_state_file(&sb, state, "sign", 1);
|
|
|
|
state->signoff = !strcmp(sb.buf, "t");
|
|
|
|
|
2015-08-04 15:51:45 +02:00
|
|
|
read_state_file(&sb, state, "utf8", 1);
|
|
|
|
state->utf8 = !strcmp(sb.buf, "t");
|
|
|
|
|
2017-08-02 12:44:15 +02:00
|
|
|
if (file_exists(am_path(state, "rerere-autoupdate"))) {
|
|
|
|
read_state_file(&sb, state, "rerere-autoupdate", 1);
|
|
|
|
state->allow_rerere_autoupdate = strcmp(sb.buf, "t") ?
|
|
|
|
RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE;
|
|
|
|
} else {
|
|
|
|
state->allow_rerere_autoupdate = 0;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:46 +02:00
|
|
|
read_state_file(&sb, state, "keep", 1);
|
|
|
|
if (!strcmp(sb.buf, "t"))
|
|
|
|
state->keep = KEEP_TRUE;
|
|
|
|
else if (!strcmp(sb.buf, "b"))
|
|
|
|
state->keep = KEEP_NON_PATCH;
|
|
|
|
else
|
|
|
|
state->keep = KEEP_FALSE;
|
|
|
|
|
2015-08-04 15:51:47 +02:00
|
|
|
read_state_file(&sb, state, "messageid", 1);
|
|
|
|
state->message_id = !strcmp(sb.buf, "t");
|
|
|
|
|
2015-08-04 15:51:49 +02:00
|
|
|
read_state_file(&sb, state, "scissors", 1);
|
|
|
|
if (!strcmp(sb.buf, "t"))
|
|
|
|
state->scissors = SCISSORS_TRUE;
|
|
|
|
else if (!strcmp(sb.buf, "f"))
|
|
|
|
state->scissors = SCISSORS_FALSE;
|
|
|
|
else
|
|
|
|
state->scissors = SCISSORS_UNSET;
|
|
|
|
|
2021-05-09 19:12:13 +02:00
|
|
|
read_state_file(&sb, state, "quoted-cr", 1);
|
|
|
|
if (!*sb.buf)
|
|
|
|
state->quoted_cr = quoted_cr_unset;
|
|
|
|
else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0)
|
|
|
|
die(_("could not parse %s"), am_path(state, "quoted-cr"));
|
|
|
|
|
builtin-am: pass git-apply's options to git-apply
git-am.sh recognizes some of git-apply's options, and would pass them to
git-apply:
* --whitespace, since 8c31cb8 (git-am: --whitespace=x option.,
2006-02-28)
* -C, since 67dad68 (add -C[NUM] to git-am, 2007-02-08)
* -p, since 2092a1f (Teach git-am to pass -p option down to git-apply,
2007-02-11)
* --directory, since b47dfe9 (git-am: add --directory=<dir> option,
2009-01-11)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
* --ignore-space-change, --ignore-whitespace, since 86c91f9 (git apply:
option to ignore whitespace differences, 2009-08-04)
* --exclude, since 77e9e49 (am: pass exclude down to apply, 2011-08-03)
* --include, since 58725ef (am: support --include option, 2012-03-28)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
Re-implement support for these options in builtin/am.c.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:50 +02:00
|
|
|
read_state_file(&sb, state, "apply-opt", 1);
|
2020-07-28 22:24:27 +02:00
|
|
|
strvec_clear(&state->git_apply_opts);
|
2020-07-28 22:24:02 +02:00
|
|
|
if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0)
|
builtin-am: pass git-apply's options to git-apply
git-am.sh recognizes some of git-apply's options, and would pass them to
git-apply:
* --whitespace, since 8c31cb8 (git-am: --whitespace=x option.,
2006-02-28)
* -C, since 67dad68 (add -C[NUM] to git-am, 2007-02-08)
* -p, since 2092a1f (Teach git-am to pass -p option down to git-apply,
2007-02-11)
* --directory, since b47dfe9 (git-am: add --directory=<dir> option,
2009-01-11)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
* --ignore-space-change, --ignore-whitespace, since 86c91f9 (git apply:
option to ignore whitespace differences, 2009-08-04)
* --exclude, since 77e9e49 (am: pass exclude down to apply, 2011-08-03)
* --include, since 58725ef (am: support --include option, 2012-03-28)
* --reject, since b80da42 (git-am: implement --reject option passed to
git-apply, 2009-01-23)
Re-implement support for these options in builtin/am.c.
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:50 +02:00
|
|
|
die(_("could not parse %s"), am_path(state, "apply-opt"));
|
|
|
|
|
2015-08-04 15:51:42 +02:00
|
|
|
state->rebasing = !!file_exists(am_path(state, "rebasing"));
|
|
|
|
|
builtin-am: implement patch queue mechanism
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.
Implement the mechanism of a "patch queue", represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:
* am_setup(), which will set up the state directory
$GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
the last-known state will still persist.
* am_load(), which is called if there is an am session in
progress, to load the last known state from the state directory so we
can resume applying patches.
* am_run(), which will do the actual patch application. After applying a
patch, it calls am_next() to increment the current patch index. The
logic for applying and committing a patch is not implemented yet.
* am_destroy(), which is finally called when we successfully applied all
the patches in the queue, to clean up by removing the state directory
and its contents.
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Stefan Beller <sbeller@google.com>
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Paul Tan <pyokagan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-08-04 15:51:25 +02:00
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes the am_state directory, forcefully terminating the current am
|
|
|
|
* session.
|
|
|
|
*/
|
|
|
|
static void am_destroy(const struct am_state *state)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addstr(&sb, state->dir);
|
|
|
|
remove_dir_recursively(&sb, 0);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:56 +02:00
|
|
|
/**
|
|
|
|
* Runs applypatch-msg hook. Returns its exit code.
|
|
|
|
*/
|
|
|
|
static int run_applypatch_msg_hook(struct am_state *state)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
assert(state->msg);
|
|
|
|
ret = run_hook_le(NULL, "applypatch-msg", am_path(state, "final-commit"), NULL);
|
|
|
|
|
|
|
|
if (!ret) {
|
2017-06-16 01:15:46 +02:00
|
|
|
FREE_AND_NULL(state->msg);
|
2015-08-04 15:51:56 +02:00
|
|
|
if (read_commit_msg(state) < 0)
|
|
|
|
die(_("'%s' was deleted by the applypatch-msg hook"),
|
|
|
|
am_path(state, "final-commit"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:54 +02:00
|
|
|
/**
|
|
|
|
* Runs post-rewrite hook. Returns it exit code.
|
|
|
|
*/
|
|
|
|
static int run_post_rewrite_hook(const struct am_state *state)
|
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
const char *hook = find_hook("post-rewrite");
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!hook)
|
|
|
|
return 0;
|
|
|
|
|
2020-07-28 22:24:27 +02:00
|
|
|
strvec_push(&cp.args, hook);
|
|
|
|
strvec_push(&cp.args, "rebase");
|
2015-08-04 15:51:54 +02:00
|
|
|
|
|
|
|
cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
|
|
|
|
cp.stdout_to_stderr = 1;
|
2019-02-22 23:25:06 +01:00
|
|
|
cp.trace2_hook_name = "post-rewrite";
|
2015-08-04 15:51:54 +02:00
|
|
|
|
|
|
|
ret = run_command(&cp);
|
|
|
|
|
|
|
|
close(cp.in);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:55 +02:00
|
|
|
/**
|
|
|
|
* Reads the state directory's "rewritten" file, and copies notes from the old
|
|
|
|
* commits listed in the file to their rewritten commits.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure.
|
|
|
|
*/
|
|
|
|
static int copy_notes_for_rebase(const struct am_state *state)
|
|
|
|
{
|
|
|
|
struct notes_rewrite_cfg *c;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
const char *invalid_line = _("Malformed input line: '%s'.");
|
|
|
|
const char *msg = "Notes added by 'git rebase'";
|
|
|
|
FILE *fp;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
assert(state->rebasing);
|
|
|
|
|
|
|
|
c = init_copy_notes_for_rewrite("rebase");
|
|
|
|
if (!c)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fp = xfopen(am_path(state, "rewritten"), "r");
|
|
|
|
|
2016-01-14 00:31:17 +01:00
|
|
|
while (!strbuf_getline_lf(&sb, fp)) {
|
2016-09-05 22:08:09 +02:00
|
|
|
struct object_id from_obj, to_obj;
|
2019-02-19 01:05:07 +01:00
|
|
|
const char *p;
|
2015-08-04 15:51:55 +02:00
|
|
|
|
2019-02-19 01:05:07 +01:00
|
|
|
if (sb.len != the_hash_algo->hexsz * 2 + 1) {
|
2015-08-04 15:51:55 +02:00
|
|
|
ret = error(invalid_line, sb.buf);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2019-02-19 01:05:07 +01:00
|
|
|
if (parse_oid_hex(sb.buf, &from_obj, &p)) {
|
2015-08-04 15:51:55 +02:00
|
|
|
ret = error(invalid_line, sb.buf);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2019-02-19 01:05:07 +01:00
|
|
|
if (*p != ' ') {
|
2015-08-04 15:51:55 +02:00
|
|
|
ret = error(invalid_line, sb.buf);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2019-02-19 01:05:07 +01:00
|
|
|
if (get_oid_hex(p + 1, &to_obj)) {
|
2015-08-04 15:51:55 +02:00
|
|
|
ret = error(invalid_line, sb.buf);
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2017-05-30 19:30:42 +02:00
|
|
|
if (copy_note_for_rewrite(c, &from_obj, &to_obj))
|
2015-08-04 15:51:55 +02:00
|
|
|
ret = error(_("Failed to copy notes from '%s' to '%s'"),
|
2016-09-05 22:08:09 +02:00
|
|
|
oid_to_hex(&from_obj), oid_to_hex(&to_obj));
|
2015-08-04 15:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
finish:
|
2019-01-12 03:13:23 +01:00
|
|
|
finish_copy_notes_for_rewrite(the_repository, c, msg);
|
2015-08-04 15:51:55 +02:00
|
|
|
fclose(fp);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:51:27 +02:00
|
|
|
/**
|
|
|
|
* Determines if the file looks like a piece of RFC2822 mail by grabbing all
|
|
|
|
* non-indented lines and checking if they look like they begin with valid
|
|
|
|
* header field names.
|
|
|
|
*
|
|
|
|
* Returns 1 if the file looks like a piece of mail, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int is_mail(FILE *fp)
|
|
|
|
{
|
|
|
|
const char *header_regex = "^[!-9;-~]+:";
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
regex_t regex;
|
|
|
|
int ret = 1;
|
|
|
|
|
|
|
|
if (fseek(fp, 0L, SEEK_SET))
|
|
|
|
die_errno(_("fseek failed"));
|
|
|
|
|
|
|
|
if (regcomp(®ex, header_regex, REG_NOSUB | REG_EXTENDED))
|
|
|
|
die("invalid pattern: %s", header_regex);
|
|
|
|
|
2016-01-14 03:32:23 +01:00
|
|
|
while (!strbuf_getline(&sb, fp)) {
|
2015-08-04 15:51:27 +02:00
|
|
|
if (!sb.len)
|
|
|
|
break; /* End of header */
|
|
|
|
|
|
|
|
/* Ignore indented folded lines */
|
|
|
|
if (*sb.buf == '\t' || *sb.buf == ' ')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* It's a header if it matches header_regex */
|
|
|
|
if (regexec(®ex, sb.buf, 0, NULL, 0)) {
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
regfree(®ex);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attempts to detect the patch_format of the patches contained in `paths`,
|
|
|
|
* returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if
|
|
|
|
* detection fails.
|
|
|
|
*/
|
|
|
|
static int detect_patch_format(const char **paths)
|
|
|
|
{
|
|
|
|
enum patch_format ret = PATCH_FORMAT_UNKNOWN;
|
|
|
|
struct strbuf l1 = STRBUF_INIT;
|
2015-08-04 15:52:00 +02:00
|
|
|
struct strbuf l2 = STRBUF_INIT;
|
|
|
|
struct strbuf l3 = STRBUF_INIT;
|
2015-08-04 15:51:27 +02:00
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We default to mbox format if input is from stdin and for directories
|
|
|
|
*/
|
|
|
|
if (!*paths || !strcmp(*paths, "-") || is_directory(*paths))
|
|
|
|
return PATCH_FORMAT_MBOX;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, check the first few lines of the first patch, starting
|
|
|
|
* from the first non-blank line, to try to detect its format.
|
|
|
|
*/
|
|
|
|
|
|
|
|
fp = xfopen(*paths, "r");
|
|
|
|
|
2016-01-14 03:32:23 +01:00
|
|
|
while (!strbuf_getline(&l1, fp)) {
|
2015-08-04 15:51:27 +02:00
|
|
|
if (l1.len)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (starts_with(l1.buf, "From ") || starts_with(l1.buf, "From: ")) {
|
|
|
|
ret = PATCH_FORMAT_MBOX;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2015-08-04 15:52:01 +02:00
|
|
|
if (starts_with(l1.buf, "# This series applies on GIT commit")) {
|
|
|
|
ret = PATCH_FORMAT_STGIT_SERIES;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|