2008-07-07 17:24:20 +00:00
|
|
|
/*
|
|
|
|
* Builtin "git merge"
|
|
|
|
*
|
|
|
|
* Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org>
|
|
|
|
*
|
|
|
|
* Based on git-merge.sh by Junio C Hamano.
|
|
|
|
*/
|
|
|
|
|
2023-02-10 10:28:39 +00:00
|
|
|
#define USE_THE_INDEX_VARIABLE
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "cache.h"
|
2023-03-21 06:25:58 +00:00
|
|
|
#include "abspath.h"
|
2023-02-24 00:09:24 +00:00
|
|
|
#include "alloc.h"
|
2017-06-14 18:07:36 +00:00
|
|
|
#include "config.h"
|
2023-03-21 06:25:57 +00:00
|
|
|
#include "environment.h"
|
2023-03-21 06:25:54 +00:00
|
|
|
#include "gettext.h"
|
2023-02-24 00:09:27 +00:00
|
|
|
#include "hex.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "parse-options.h"
|
|
|
|
#include "builtin.h"
|
2014-10-01 10:28:42 +00:00
|
|
|
#include "lockfile.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "run-command.h"
|
2021-09-26 19:03:26 +00:00
|
|
|
#include "hook.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "diff.h"
|
2020-12-21 15:19:38 +00:00
|
|
|
#include "diff-merges.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "refs.h"
|
2018-05-16 22:57:48 +00:00
|
|
|
#include "refspec.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
#include "commit.h"
|
|
|
|
#include "diffcore.h"
|
|
|
|
#include "revision.h"
|
|
|
|
#include "unpack-trees.h"
|
|
|
|
#include "cache-tree.h"
|
|
|
|
#include "dir.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
#include "log-tree.h"
|
|
|
|
#include "color.h"
|
2008-07-16 02:09:46 +00:00
|
|
|
#include "rerere.h"
|
2008-07-29 23:16:59 +00:00
|
|
|
#include "help.h"
|
2008-08-28 13:43:00 +00:00
|
|
|
#include "merge-recursive.h"
|
2020-11-02 23:45:34 +00:00
|
|
|
#include "merge-ort-wrappers.h"
|
2009-12-25 08:30:51 +00:00
|
|
|
#include "resolve-undo.h"
|
2011-03-24 06:48:24 +00:00
|
|
|
#include "remote.h"
|
2011-10-07 06:12:09 +00:00
|
|
|
#include "fmt-merge-msg.h"
|
commit: teach --gpg-sign option
This uses the gpg-interface.[ch] to allow signing the commit, i.e.
$ git commit --gpg-sign -m foo
You need a passphrase to unlock the secret key for
user: "Junio C Hamano <gitster@pobox.com>"
4096-bit RSA key, ID 96AFE6CB, created 2011-10-03 (main key ID 713660A7)
[master 8457d13] foo
1 files changed, 1 insertions(+), 0 deletions(-)
The lines of GPG detached signature are placed in a new multi-line header
field, instead of tucking the signature block at the end of the commit log
message text (similar to how signed tag is done), for multiple reasons:
- The signature won't clutter output from "git log" and friends if it is
in the extra header. If we place it at the end of the log message, we
would need to teach "git log" and friends to strip the signature block
with an option.
- Teaching new versions of "git log" and "gitk" to optionally verify and
show signatures is cleaner if we structurally know where the signature
block is (instead of scanning in the commit log message).
- The signature needs to be stripped upon various commit rewriting
operations, e.g. rebase, filter-branch, etc. They all already ignore
unknown headers, but if we place signature in the log message, all of
these tools (and third-party tools) also need to learn how a signature
block would look like.
- When we added the optional encoding header, all the tools (both in tree
and third-party) that acts on the raw commit object should have been
fixed to ignore headers they do not understand, so it is not like that
new header would be more likely to break than extra text in the commit.
A commit made with the above sample sequence would look like this:
$ git cat-file commit HEAD
tree 3cd71d90e3db4136e5260ab54599791c4f883b9d
parent b87755351a47b09cb27d6913e6e0e17e6254a4d4
author Junio C Hamano <gitster@pobox.com> 1317862251 -0700
committer Junio C Hamano <gitster@pobox.com> 1317862251 -0700
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iQIcBAABAgAGBQJOjPtrAAoJELC16IaWr+bL4TMP/RSe2Y/jYnCkds9unO5JEnfG
...
=dt98
-----END PGP SIGNATURE-----
foo
but "git log" (unless you ask for it with --pretty=raw) output is not
cluttered with the signature information.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-06 00:23:20 +00:00
|
|
|
#include "gpg-interface.h"
|
2014-10-24 18:34:59 +00:00
|
|
|
#include "sequencer.h"
|
2016-08-05 21:01:35 +00:00
|
|
|
#include "string-list.h"
|
2017-08-18 22:20:21 +00:00
|
|
|
#include "packfile.h"
|
2018-02-14 18:18:55 +00:00
|
|
|
#include "tag.h"
|
2018-05-20 18:40:06 +00:00
|
|
|
#include "alias.h"
|
2019-05-09 10:10:27 +00:00
|
|
|
#include "branch.h"
|
2018-07-20 16:33:04 +00:00
|
|
|
#include "commit-reach.h"
|
2019-04-17 10:23:27 +00:00
|
|
|
#include "wt-status.h"
|
2020-04-16 20:14:03 +00:00
|
|
|
#include "commit-graph.h"
|
2023-03-21 06:26:01 +00:00
|
|
|
#include "wrapper.h"
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
#define DEFAULT_TWOHEAD (1<<0)
|
|
|
|
#define DEFAULT_OCTOPUS (1<<1)
|
|
|
|
#define NO_FAST_FORWARD (1<<2)
|
|
|
|
#define NO_TRIVIAL (1<<3)
|
|
|
|
|
|
|
|
struct strategy {
|
|
|
|
const char *name;
|
|
|
|
unsigned attr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const builtin_merge_usage[] = {
|
2015-01-13 07:44:47 +00:00
|
|
|
N_("git merge [<options>] [<commit>...]"),
|
2021-05-15 20:01:11 +00:00
|
|
|
"git merge --abort",
|
|
|
|
"git merge --continue",
|
2008-07-07 17:24:20 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2011-10-07 06:12:09 +00:00
|
|
|
static int show_diffstat = 1, shortlog_len = -1, squash;
|
2019-05-24 18:36:17 +00:00
|
|
|
static int option_commit = -1;
|
2013-07-02 14:47:57 +00:00
|
|
|
static int option_edit = -1;
|
2013-03-31 16:02:24 +00:00
|
|
|
static int allow_trivial = 1, have_message, verify_signatures;
|
gpg-interface: add minTrustLevel as a configuration option
Previously, signature verification for merge and pull operations checked
if the key had a trust-level of either TRUST_NEVER or TRUST_UNDEFINED in
verify_merge_signature(). If that was the case, the process die()d.
The other code paths that did signature verification relied entirely on
the return code from check_commit_signature(). And signatures made with
a good key, irregardless of its trust level, was considered valid by
check_commit_signature().
This difference in behavior might induce users to erroneously assume
that the trust level of a key in their keyring is always considered by
Git, even for operations where it is not (e.g. during a verify-commit or
verify-tag).
The way it worked was by gpg-interface.c storing the result from the
key/signature status *and* the lowest-two trust levels in the `result`
member of the signature_check structure (the last of these status lines
that were encountered got written to `result`). These are documented in
GPG under the subsection `General status codes` and `Key related`,
respectively [1].
The GPG documentation says the following on the TRUST_ status codes [1]:
"""
These are several similar status codes:
- TRUST_UNDEFINED <error_token>
- TRUST_NEVER <error_token>
- TRUST_MARGINAL [0 [<validation_model>]]
- TRUST_FULLY [0 [<validation_model>]]
- TRUST_ULTIMATE [0 [<validation_model>]]
For good signatures one of these status lines are emitted to
indicate the validity of the key used to create the signature.
The error token values are currently only emitted by gpgsm.
"""
My interpretation is that the trust level is conceptionally different
from the validity of the key and/or signature. That seems to also have
been the assumption of the old code in check_signature() where a result
of 'G' (as in GOODSIG) and 'U' (as in TRUST_NEVER or TRUST_UNDEFINED)
were both considered a success.
The two cases where a result of 'U' had special meaning were in
verify_merge_signature() (where this caused git to die()) and in
format_commit_one() (where it affected the output of the %G? format
specifier).
I think it makes sense to refactor the processing of TRUST_ status lines
such that users can configure a minimum trust level that is enforced
globally, rather than have individual parts of git (e.g. merge) do it
themselves (except for a grace period with backward compatibility).
I also think it makes sense to not store the trust level in the same
struct member as the key/signature status. While the presence of a
TRUST_ status code does imply that the signature is good (see the first
paragraph in the included snippet above), as far as I can tell, the
order of the status lines from GPG isn't well-defined; thus it would
seem plausible that the trust level could be overwritten with the
key/signature status if they were stored in the same member of the
signature_check structure.
This patch introduces a new configuration option: gpg.minTrustLevel. It
consolidates trust-level verification to gpg-interface.c and adds a new
`trust_level` member to the signature_check structure.
Backward-compatibility is maintained by introducing a special case in
verify_merge_signature() such that if no user-configurable
gpg.minTrustLevel is set, then the old behavior of rejecting
TRUST_UNDEFINED and TRUST_NEVER is enforced. If, on the other hand,
gpg.minTrustLevel is set, then that value overrides the old behavior.
Similarly, the %G? format specifier will continue show 'U' for
signatures made with a key that has a trust level of TRUST_UNDEFINED or
TRUST_NEVER, even though the 'U' character no longer exist in the
`result` member of the signature_check structure. A new format
specifier, %GT, is also introduced for users that want to show all
possible trust levels for a signature.
Another approach would have been to simply drop the trust-level
requirement in verify_merge_signature(). This would also have made the
behavior consistent with other parts of git that perform signature
verification. However, requiring a minimum trust level for signing keys
does seem to have a real-world use-case. For example, the build system
used by the Qubes OS project currently parses the raw output from
verify-tag in order to assert a minimum trust level for keys used to
sign git tags [2].
[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/doc/DETAILS;h=bd00006e933ac56719b1edd2478ecd79273eae72;hb=refs/heads/master
[2] https://github.com/QubesOS/qubes-builder/blob/9674c1991deef45b1a1b1c71fddfab14ba50dccf/scripts/verify-git-tag#L43
Signed-off-by: Hans Jerry Illikainen <hji@dyntopia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-27 13:55:57 +00:00
|
|
|
static int check_trust_level = 1;
|
2011-11-27 10:15:33 +00:00
|
|
|
static int overwrite_ignore = 1;
|
2011-12-18 05:03:22 +00:00
|
|
|
static struct strbuf merge_msg = STRBUF_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
static struct strategy **use_strategies;
|
|
|
|
static size_t use_strategies_nr, use_strategies_alloc;
|
2009-11-26 02:23:55 +00:00
|
|
|
static const char **xopts;
|
|
|
|
static size_t xopts_nr, xopts_alloc;
|
2008-07-07 17:24:20 +00:00
|
|
|
static const char *branch;
|
2011-05-05 00:42:51 +00:00
|
|
|
static char *branch_mergeoptions;
|
2008-11-15 00:14:24 +00:00
|
|
|
static int verbosity;
|
2009-12-04 08:20:48 +00:00
|
|
|
static int allow_rerere_auto;
|
2010-11-09 21:49:59 +00:00
|
|
|
static int abort_current_merge;
|
merge: add --quit
This allows to cancel the current merge without resetting worktree/index,
which is what --abort is for. Like other --quit(s), this is often used
when you forgot that you're in the middle of a merge and already
switched away, doing different things. By the time you've realized, you
can't even continue the merge anymore.
This also makes all in-progress commands, am, merge, rebase, revert and
cherry-pick, take all three --abort, --continue and --quit (bisect has a
different UI).
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-18 11:30:43 +00:00
|
|
|
static int quit_current_merge;
|
2016-12-14 08:37:55 +00:00
|
|
|
static int continue_current_merge;
|
merge: refuse to create too cool a merge by default
While it makes sense to allow merging unrelated histories of two
projects that started independently into one, in the way "gitk" was
merged to "git" itself aka "the coolest merge ever", such a merge is
still an unusual event. Worse, if somebody creates an independent
history by starting from a tarball of an established project and
sends a pull request to the original project, "git merge" however
happily creates such a merge without any sign of something unusual
is happening.
Teach "git merge" to refuse to create such a merge by default,
unless the user passes a new "--allow-unrelated-histories" option to
tell it that the user is aware that two unrelated projects are
merged.
Because such a "two project merge" is a rare event, a configuration
option to always allow such a merge is not added.
We could add the same option to "git pull" and have it passed
through to underlying "git merge". I do not have a fundamental
opposition against such a feature, but this commit does not do so
and instead leaves it as low-hanging fruit for others, because such
a "two project merge" would be done after fetching the other project
into some location in the working tree of an existing project and
making sure how well they fit together, it is sufficient to allow a
local merge without such an option pass-through from "git pull" to
"git merge". Many tests that are updated by this patch does the
pass-through manually by turning:
git pull something
into its equivalent:
git fetch something &&
git merge --allow-unrelated-histories FETCH_HEAD
If somebody is inclined to add such an option, updated tests in this
change need to be adjusted back to:
git pull --allow-unrelated-histories something
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-18 20:21:09 +00:00
|
|
|
static int allow_unrelated_histories;
|
2011-02-20 09:53:21 +00:00
|
|
|
static int show_progress = -1;
|
2014-04-21 00:17:33 +00:00
|
|
|
static int default_to_upstream = 1;
|
2017-07-04 09:33:06 +00:00
|
|
|
static int signoff;
|
commit: teach --gpg-sign option
This uses the gpg-interface.[ch] to allow signing the commit, i.e.
$ git commit --gpg-sign -m foo
You need a passphrase to unlock the secret key for
user: "Junio C Hamano <gitster@pobox.com>"
4096-bit RSA key, ID 96AFE6CB, created 2011-10-03 (main key ID 713660A7)
[master 8457d13] foo
1 files changed, 1 insertions(+), 0 deletions(-)
The lines of GPG detached signature are placed in a new multi-line header
field, instead of tucking the signature block at the end of the commit log
message text (similar to how signed tag is done), for multiple reasons:
- The signature won't clutter output from "git log" and friends if it is
in the extra header. If we place it at the end of the log message, we
would need to teach "git log" and friends to strip the signature block
with an option.
- Teaching new versions of "git log" and "gitk" to optionally verify and
show signatures is cleaner if we structurally know where the signature
block is (instead of scanning in the commit log message).
- The signature needs to be stripped upon various commit rewriting
operations, e.g. rebase, filter-branch, etc. They all already ignore
unknown headers, but if we place signature in the log message, all of
these tools (and third-party tools) also need to learn how a signature
block would look like.
- When we added the optional encoding header, all the tools (both in tree
and third-party) that acts on the raw commit object should have been
fixed to ignore headers they do not understand, so it is not like that
new header would be more likely to break than extra text in the commit.
A commit made with the above sample sequence would look like this:
$ git cat-file commit HEAD
tree 3cd71d90e3db4136e5260ab54599791c4f883b9d
parent b87755351a47b09cb27d6913e6e0e17e6254a4d4
author Junio C Hamano <gitster@pobox.com> 1317862251 -0700
committer Junio C Hamano <gitster@pobox.com> 1317862251 -0700
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iQIcBAABAgAGBQJOjPtrAAoJELC16IaWr+bL4TMP/RSe2Y/jYnCkds9unO5JEnfG
...
=dt98
-----END PGP SIGNATURE-----
foo
but "git log" (unless you ask for it with --pretty=raw) output is not
cluttered with the signature information.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-06 00:23:20 +00:00
|
|
|
static const char *sign_commit;
|
2020-04-07 14:28:07 +00:00
|
|
|
static int autostash;
|
2019-08-07 18:57:06 +00:00
|
|
|
static int no_verify;
|
merge: allow to pretend a merge is made into a different branch
When a series of patches for a topic-B depends on having topic-A,
the workflow to prepare the topic-B branch would look like this:
$ git checkout -b topic-B main
$ git merge --no-ff --no-edit topic-A
$ git am <mbox-for-topic-B
When topic-A gets updated, recreating the first merge and rebasing
the rest of the topic-B, all on detached HEAD, is a useful
technique. After updating topic-A with its new round of patches:
$ git checkout topic-B
$ prev=$(git rev-parse 'HEAD^{/^Merge branch .topic-A. into}')
$ git checkout --detach $prev^1
$ git merge --no-ff --no-edit topic-A
$ git rebase --onto HEAD $prev @{-1}^0
$ git checkout -B @{-1}
This will
(0) check out the current topic-B.
(1) find the previous merge of topic-A into topic-B.
(2) detach the HEAD to the parent of the previous merge.
(3) merge the updated topic-A to it.
(4) reapply the patches to rebuild the rest of topic-B.
(5) update topic-B with the result.
without contaminating the reflog of topic-B too much. topic-B@{1}
is the "logically previous" state before topic-A got updated, for
example. At (4), comparison (e.g. range-diff) between HEAD and
@{-1} is a meaningful way to sanity check the result, and the same
can be done at (5) by comparing topic-B and topic-B@{1}.
But there is one glitch. The merge into the detached HEAD done in
the step (3) above gives us "Merge branch 'topic-A' into HEAD", and
does not say "into topic-B".
Teach the "--into-name=<branch>" option to "git merge" and its
underlying "git fmt-merge-message", to pretend as if we were merging
into <branch>, no matter what branch we are actually merging into,
when they prepare the merge message. The pretend name honors the
usual "into <target>" suppression mechanism, which can be seen in
the tests added here.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-20 22:53:43 +00:00
|
|
|
static char *into_name;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
static struct strategy all_strategy[] = {
|
Change default merge backend from recursive to ort
There are a few reasons to switch the default:
* Correctness
* Extensibility
* Performance
I'll provide some summaries about each.
=== Correctness ===
The original impetus for a new merge backend was to fix issues that were
difficult to fix within recursive's design. The success with this goal
is perhaps most easily demonstrated by running the following:
$ git grep -2 KNOWN_FAILURE t/ | grep -A 4 GIT_TEST_MERGE_ALGORITHM
$ git grep test_expect_merge_algorithm.failure.success t/
$ git grep test_expect_merge_algorithm.success.failure t/
In order, these greps show:
* Seven sets of submodule tests (10 total tests) that fail with
recursive but succeed with ort
* 22 other tests that fail with recursive, but succeed with ort
* 0 tests that pass with recursive, but fail with ort
=== Extensibility ===
Being able to perform merges without touching the working tree or index
makes it possible to create new features that were difficult with the
old backend:
* Merging, cherry-picking, rebasing, reverting in bare repositories...
or just on branches that aren't checked out.
* `git diff AUTO_MERGE` -- ability to see what changes the user has
made to resolve conflicts so far (see commit 5291828df8 ("merge-ort:
write $GIT_DIR/AUTO_MERGE whenever we hit a conflict", 2021-03-20)
* A --remerge-diff option for log/show, used to show diffs for merges
that display the difference between what an automatic merge would
have created and what was recorded in the merge. (This option will
often result in an empty diff because many merges are clean, but for
the non-clean ones it will show how conflicts were fixed including
the removal of conflict markers, and also show additional changes
made outside of conflict regions to e.g. fix semantic conflicts.)
* A --remerge-diff-only option for log/show, similar to --remerge-diff
but also showing how cherry-picks or reverts differed from what an
automatic cherry-pick or revert would provide.
The last three have been implemented already (though only one has been
submitted upstream so far; the others were waiting for performance work
to complete), and I still plan to implement the first one.
=== Performance ===
I'll quote from the summary of my final optimization for merge-ort
(while fixing the testcase name from 'no-renames' to 'few-renames'):
Timings
Infinite
merge- merge- Parallelism
recursive recursive of rename merge-ort
v2.30.0 current detection current
---------- --------- ----------- ---------
few-renames: 18.912 s 18.030 s 11.699 s 198.3 ms
mega-renames: 5964.031 s 361.281 s 203.886 s 661.8 ms
just-one-mega: 149.583 s 11.009 s 7.553 s 264.6 ms
Speedup factors
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
few-renames: 1 1.05 1.6 95
mega-renames: 1 16.5 29 9012
just-one-mega: 1 13.6 20 565
And, for partial clone users:
Factor reduction in number of objects needed
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
mega-renames: 1 1 1 181.3
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-08-04 05:38:01 +00:00
|
|
|
{ "recursive", NO_TRIVIAL },
|
2008-07-07 17:24:20 +00:00
|
|
|
{ "octopus", DEFAULT_OCTOPUS },
|
Change default merge backend from recursive to ort
There are a few reasons to switch the default:
* Correctness
* Extensibility
* Performance
I'll provide some summaries about each.
=== Correctness ===
The original impetus for a new merge backend was to fix issues that were
difficult to fix within recursive's design. The success with this goal
is perhaps most easily demonstrated by running the following:
$ git grep -2 KNOWN_FAILURE t/ | grep -A 4 GIT_TEST_MERGE_ALGORITHM
$ git grep test_expect_merge_algorithm.failure.success t/
$ git grep test_expect_merge_algorithm.success.failure t/
In order, these greps show:
* Seven sets of submodule tests (10 total tests) that fail with
recursive but succeed with ort
* 22 other tests that fail with recursive, but succeed with ort
* 0 tests that pass with recursive, but fail with ort
=== Extensibility ===
Being able to perform merges without touching the working tree or index
makes it possible to create new features that were difficult with the
old backend:
* Merging, cherry-picking, rebasing, reverting in bare repositories...
or just on branches that aren't checked out.
* `git diff AUTO_MERGE` -- ability to see what changes the user has
made to resolve conflicts so far (see commit 5291828df8 ("merge-ort:
write $GIT_DIR/AUTO_MERGE whenever we hit a conflict", 2021-03-20)
* A --remerge-diff option for log/show, used to show diffs for merges
that display the difference between what an automatic merge would
have created and what was recorded in the merge. (This option will
often result in an empty diff because many merges are clean, but for
the non-clean ones it will show how conflicts were fixed including
the removal of conflict markers, and also show additional changes
made outside of conflict regions to e.g. fix semantic conflicts.)
* A --remerge-diff-only option for log/show, similar to --remerge-diff
but also showing how cherry-picks or reverts differed from what an
automatic cherry-pick or revert would provide.
The last three have been implemented already (though only one has been
submitted upstream so far; the others were waiting for performance work
to complete), and I still plan to implement the first one.
=== Performance ===
I'll quote from the summary of my final optimization for merge-ort
(while fixing the testcase name from 'no-renames' to 'few-renames'):
Timings
Infinite
merge- merge- Parallelism
recursive recursive of rename merge-ort
v2.30.0 current detection current
---------- --------- ----------- ---------
few-renames: 18.912 s 18.030 s 11.699 s 198.3 ms
mega-renames: 5964.031 s 361.281 s 203.886 s 661.8 ms
just-one-mega: 149.583 s 11.009 s 7.553 s 264.6 ms
Speedup factors
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
few-renames: 1 1.05 1.6 95
mega-renames: 1 16.5 29 9012
just-one-mega: 1 13.6 20 565
And, for partial clone users:
Factor reduction in number of objects needed
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
mega-renames: 1 1 1 181.3
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-08-04 05:38:01 +00:00
|
|
|
{ "ort", DEFAULT_TWOHEAD | NO_TRIVIAL },
|
2008-07-07 17:24:20 +00:00
|
|
|
{ "resolve", 0 },
|
|
|
|
{ "ours", NO_FAST_FORWARD | NO_TRIVIAL },
|
|
|
|
{ "subtree", NO_FAST_FORWARD | NO_TRIVIAL },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *pull_twohead, *pull_octopus;
|
|
|
|
|
2013-07-02 14:47:57 +00:00
|
|
|
enum ff_type {
|
|
|
|
FF_NO,
|
|
|
|
FF_ALLOW,
|
|
|
|
FF_ONLY
|
|
|
|
};
|
|
|
|
|
|
|
|
static enum ff_type fast_forward = FF_ALLOW;
|
|
|
|
|
2019-04-17 10:23:27 +00:00
|
|
|
static const char *cleanup_arg;
|
|
|
|
static enum commit_msg_cleanup_mode cleanup_mode;
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
static int option_parse_message(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct strbuf *buf = opt->value;
|
|
|
|
|
|
|
|
if (unset)
|
|
|
|
strbuf_setlen(buf, 0);
|
2008-07-20 12:34:47 +00:00
|
|
|
else if (arg) {
|
2009-12-02 18:00:58 +00:00
|
|
|
strbuf_addf(buf, "%s%s", buf->len ? "\n\n" : "", arg);
|
2008-07-07 17:24:20 +00:00
|
|
|
have_message = 1;
|
2008-07-20 12:34:47 +00:00
|
|
|
} else
|
2011-02-22 23:41:59 +00:00
|
|
|
return error(_("switch `m' requires a value"));
|
2008-07-07 17:24:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-27 00:35:27 +00:00
|
|
|
static enum parse_opt_result option_read_message(struct parse_opt_ctx_t *ctx,
|
|
|
|
const struct option *opt,
|
2019-01-27 00:35:28 +00:00
|
|
|
const char *arg_not_used,
|
2019-01-27 00:35:27 +00:00
|
|
|
int unset)
|
2017-12-22 14:10:02 +00:00
|
|
|
{
|
|
|
|
struct strbuf *buf = opt->value;
|
|
|
|
const char *arg;
|
|
|
|
|
2019-01-27 00:35:28 +00:00
|
|
|
BUG_ON_OPT_ARG(arg_not_used);
|
2017-12-22 14:10:02 +00:00
|
|
|
if (unset)
|
|
|
|
BUG("-F cannot be negated");
|
|
|
|
|
|
|
|
if (ctx->opt) {
|
|
|
|
arg = ctx->opt;
|
|
|
|
ctx->opt = NULL;
|
|
|
|
} else if (ctx->argc > 1) {
|
|
|
|
ctx->argc--;
|
|
|
|
arg = *++ctx->argv;
|
|
|
|
} else
|
2018-11-10 05:16:11 +00:00
|
|
|
return error(_("option `%s' requires a value"), opt->long_name);
|
2017-12-22 14:10:02 +00:00
|
|
|
|
|
|
|
if (buf->len)
|
|
|
|
strbuf_addch(buf, '\n');
|
|
|
|
if (ctx->prefix && !is_absolute_path(arg))
|
|
|
|
arg = prefix_filename(ctx->prefix, arg);
|
|
|
|
if (strbuf_read_file(buf, arg, 0) < 0)
|
|
|
|
return error(_("could not read file '%s'"), arg);
|
|
|
|
have_message = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
static struct strategy *get_strategy(const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
2008-07-29 23:16:59 +00:00
|
|
|
struct strategy *ret;
|
|
|
|
static struct cmdnames main_cmds, other_cmds;
|
2008-08-28 17:15:33 +00:00
|
|
|
static int loaded;
|
2020-11-02 23:45:34 +00:00
|
|
|
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
if (!name)
|
|
|
|
return NULL;
|
|
|
|
|
2020-11-02 23:45:34 +00:00
|
|
|
if (default_strategy &&
|
|
|
|
!strcmp(default_strategy, "ort") &&
|
|
|
|
!strcmp(name, "recursive")) {
|
|
|
|
name = "ort";
|
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
|
|
|
|
if (!strcmp(name, all_strategy[i].name))
|
|
|
|
return &all_strategy[i];
|
2008-07-21 16:10:47 +00:00
|
|
|
|
2008-08-28 17:15:33 +00:00
|
|
|
if (!loaded) {
|
2008-07-29 23:16:59 +00:00
|
|
|
struct cmdnames not_strategies;
|
2008-08-28 17:15:33 +00:00
|
|
|
loaded = 1;
|
2008-07-29 23:16:59 +00:00
|
|
|
|
|
|
|
memset(¬_strategies, 0, sizeof(struct cmdnames));
|
2008-08-28 17:15:33 +00:00
|
|
|
load_command_list("git-merge-", &main_cmds, &other_cmds);
|
2008-07-29 23:16:59 +00:00
|
|
|
for (i = 0; i < main_cmds.cnt; i++) {
|
|
|
|
int j, found = 0;
|
|
|
|
struct cmdname *ent = main_cmds.names[i];
|
2023-01-09 17:34:28 +00:00
|
|
|
for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
|
2008-07-29 23:16:59 +00:00
|
|
|
if (!strncmp(ent->name, all_strategy[j].name, ent->len)
|
|
|
|
&& !all_strategy[j].name[ent->len])
|
|
|
|
found = 1;
|
|
|
|
if (!found)
|
|
|
|
add_cmdname(¬_strategies, ent->name, ent->len);
|
|
|
|
}
|
2009-11-26 02:23:54 +00:00
|
|
|
exclude_cmds(&main_cmds, ¬_strategies);
|
2008-07-29 23:16:59 +00:00
|
|
|
}
|
|
|
|
if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
|
2011-02-22 23:41:59 +00:00
|
|
|
fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name);
|
|
|
|
fprintf(stderr, _("Available strategies are:"));
|
2008-08-21 05:07:55 +00:00
|
|
|
for (i = 0; i < main_cmds.cnt; i++)
|
|
|
|
fprintf(stderr, " %s", main_cmds.names[i]->name);
|
|
|
|
fprintf(stderr, ".\n");
|
|
|
|
if (other_cmds.cnt) {
|
2011-02-22 23:41:59 +00:00
|
|
|
fprintf(stderr, _("Available custom strategies are:"));
|
2008-08-21 05:07:55 +00:00
|
|
|
for (i = 0; i < other_cmds.cnt; i++)
|
|
|
|
fprintf(stderr, " %s", other_cmds.names[i]->name);
|
|
|
|
fprintf(stderr, ".\n");
|
|
|
|
}
|
2008-07-29 23:16:59 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2021-03-13 16:17:22 +00:00
|
|
|
CALLOC_ARRAY(ret, 1);
|
2008-07-29 23:16:59 +00:00
|
|
|
ret->name = xstrdup(name);
|
2010-08-16 01:11:06 +00:00
|
|
|
ret->attr = NO_TRIVIAL;
|
2008-07-29 23:16:59 +00:00
|
|
|
return ret;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void append_strategy(struct strategy *s)
|
|
|
|
{
|
|
|
|
ALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);
|
|
|
|
use_strategies[use_strategies_nr++] = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int option_parse_strategy(const struct option *opt,
|
|
|
|
const char *name, int unset)
|
|
|
|
{
|
|
|
|
if (unset)
|
|
|
|
return 0;
|
|
|
|
|
2008-07-21 16:10:47 +00:00
|
|
|
append_strategy(get_strategy(name));
|
2008-07-07 17:24:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-26 02:23:55 +00:00
|
|
|
static int option_parse_x(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
if (unset)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
|
|
|
|
xopts[xopts_nr++] = xstrdup(arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
static int option_parse_n(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
assert NOARG/NONEG behavior of parse-options callbacks
When we define a parse-options callback, the flags we put in the option
struct must match what the callback expects. For example, a callback
which does not handle the "unset" parameter should only be used with
PARSE_OPT_NONEG. But since the callback and the option struct are not
defined next to each other, it's easy to get this wrong (as earlier
patches in this series show).
Fortunately, the compiler can help us here: compiling with
-Wunused-parameters can show us which callbacks ignore their "unset"
parameters (and likewise, ones that ignore "arg" expect to be triggered
with PARSE_OPT_NOARG).
But after we've inspected a callback and determined that all of its
callers use the right flags, what do we do next? We'd like to silence
the compiler warning, but do so in a way that will catch any wrong calls
in the future.
We can do that by actually checking those variables and asserting that
they match our expectations. Because this is such a common pattern,
we'll introduce some helper macros. The resulting messages aren't
as descriptive as we could make them, but the file/line information from
BUG() is enough to identify the problem (and anyway, the point is that
these should never be seen).
Each of the annotated callbacks in this patch triggers
-Wunused-parameters, and was manually inspected to make sure all callers
use the correct options (so none of these BUGs should be triggerable).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-11-05 06:45:42 +00:00
|
|
|
BUG_ON_OPT_ARG(arg);
|
2008-07-07 17:24:20 +00:00
|
|
|
show_diffstat = unset;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct option builtin_merge_options[] = {
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
OPT_CALLBACK_F('n', NULL, NULL, NULL,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("do not show a diffstat at the end of the merge"),
|
Use OPT_CALLBACK and OPT_CALLBACK_F
In the codebase, there are many options which use OPTION_CALLBACK in a
plain ol' struct definition. However, we have the OPT_CALLBACK and
OPT_CALLBACK_F macros which are meant to abstract these plain struct
definitions away. These macros are useful as they semantically signal to
developers that these are just normal callback option with nothing fancy
happening.
Replace plain struct definitions of OPTION_CALLBACK with OPT_CALLBACK or
OPT_CALLBACK_F where applicable. The heavy lifting was done using the
following (disgusting) shell script:
#!/bin/sh
do_replacement () {
tr '\n' '\r' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\s*0,\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK(\1,\2,\3,\4,\5,\6)/g' |
sed -e 's/{\s*OPTION_CALLBACK,\s*\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\([^,]*\),\(\s*[^[:space:]}]*\)\s*}/OPT_CALLBACK_F(\1,\2,\3,\4,\5,\6,\7)/g' |
tr '\r' '\n'
}
for f in $(git ls-files \*.c)
do
do_replacement <"$f" >"$f.tmp"
mv "$f.tmp" "$f"
done
The result was manually inspected and then reformatted to match the
style of the surrounding code. Finally, using
`git grep OPTION_CALLBACK \*.c`, leftover results which were not handled
by the script were manually transformed.
Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-04-28 08:36:28 +00:00
|
|
|
PARSE_OPT_NOARG, option_parse_n),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "stat", &show_diffstat,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("show a diffstat at the end of the merge")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
|
2012-08-20 12:32:24 +00:00
|
|
|
{ OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
|
|
|
|
N_("add (at most <n>) entries from shortlog to merge commit message"),
|
2010-09-08 17:59:54 +00:00
|
|
|
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "squash", &squash,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("create a single commit instead of doing a merge")),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "commit", &option_commit,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("perform a commit if the merge succeeds (default)")),
|
2012-01-11 06:44:45 +00:00
|
|
|
OPT_BOOL('e', "edit", &option_edit,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("edit message before committing")),
|
2019-04-17 10:23:27 +00:00
|
|
|
OPT_CLEANUP(&cleanup_arg),
|
2013-07-02 14:47:57 +00:00
|
|
|
OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
|
2018-05-20 15:42:58 +00:00
|
|
|
OPT_SET_INT_F(0, "ff-only", &fast_forward,
|
|
|
|
N_("abort if fast-forward is not possible"),
|
|
|
|
FF_ONLY, PARSE_OPT_NONEG),
|
2009-12-04 08:20:48 +00:00
|
|
|
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
|
2013-03-31 16:02:24 +00:00
|
|
|
OPT_BOOL(0, "verify-signatures", &verify_signatures,
|
2016-06-17 20:21:18 +00:00
|
|
|
N_("verify that the named commit has a valid GPG signature")),
|
2012-08-20 12:32:24 +00:00
|
|
|
OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
|
|
|
|
N_("merge strategy to use"), option_parse_strategy),
|
|
|
|
OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
|
|
|
|
N_("option for selected merge strategy"), option_parse_x),
|
|
|
|
OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
|
|
|
|
N_("merge commit message (for a non-fast-forward merge)"),
|
2008-07-07 17:24:20 +00:00
|
|
|
option_parse_message),
|
2017-12-22 14:10:02 +00:00
|
|
|
{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
|
|
|
|
N_("read message from file"), PARSE_OPT_NONEG,
|
2019-01-27 00:35:26 +00:00
|
|
|
NULL, 0, option_read_message },
|
merge: allow to pretend a merge is made into a different branch
When a series of patches for a topic-B depends on having topic-A,
the workflow to prepare the topic-B branch would look like this:
$ git checkout -b topic-B main
$ git merge --no-ff --no-edit topic-A
$ git am <mbox-for-topic-B
When topic-A gets updated, recreating the first merge and rebasing
the rest of the topic-B, all on detached HEAD, is a useful
technique. After updating topic-A with its new round of patches:
$ git checkout topic-B
$ prev=$(git rev-parse 'HEAD^{/^Merge branch .topic-A. into}')
$ git checkout --detach $prev^1
$ git merge --no-ff --no-edit topic-A
$ git rebase --onto HEAD $prev @{-1}^0
$ git checkout -B @{-1}
This will
(0) check out the current topic-B.
(1) find the previous merge of topic-A into topic-B.
(2) detach the HEAD to the parent of the previous merge.
(3) merge the updated topic-A to it.
(4) reapply the patches to rebuild the rest of topic-B.
(5) update topic-B with the result.
without contaminating the reflog of topic-B too much. topic-B@{1}
is the "logically previous" state before topic-A got updated, for
example. At (4), comparison (e.g. range-diff) between HEAD and
@{-1} is a meaningful way to sanity check the result, and the same
can be done at (5) by comparing topic-B and topic-B@{1}.
But there is one glitch. The merge into the detached HEAD done in
the step (3) above gives us "Merge branch 'topic-A' into HEAD", and
does not say "into topic-B".
Teach the "--into-name=<branch>" option to "git merge" and its
underlying "git fmt-merge-message", to pretend as if we were merging
into <branch>, no matter what branch we are actually merging into,
when they prepare the merge message. The pretend name honors the
usual "into <target>" suppression mechanism, which can be seen in
the tests added here.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-20 22:53:43 +00:00
|
|
|
OPT_STRING(0, "into-name", &into_name, N_("name"),
|
|
|
|
N_("use <name> instead of the real target")),
|
2008-11-15 00:14:24 +00:00
|
|
|
OPT__VERBOSITY(&verbosity),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "abort", &abort_current_merge,
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("abort the current in-progress merge")),
|
merge: add --quit
This allows to cancel the current merge without resetting worktree/index,
which is what --abort is for. Like other --quit(s), this is often used
when you forgot that you're in the middle of a merge and already
switched away, doing different things. By the time you've realized, you
can't even continue the merge anymore.
This also makes all in-progress commands, am, merge, rebase, revert and
cherry-pick, take all three --abort, --continue and --quit (bisect has a
different UI).
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-18 11:30:43 +00:00
|
|
|
OPT_BOOL(0, "quit", &quit_current_merge,
|
|
|
|
N_("--abort but leave index and working tree alone")),
|
2016-12-14 08:37:55 +00:00
|
|
|
OPT_BOOL(0, "continue", &continue_current_merge,
|
|
|
|
N_("continue the current in-progress merge")),
|
merge: refuse to create too cool a merge by default
While it makes sense to allow merging unrelated histories of two
projects that started independently into one, in the way "gitk" was
merged to "git" itself aka "the coolest merge ever", such a merge is
still an unusual event. Worse, if somebody creates an independent
history by starting from a tarball of an established project and
sends a pull request to the original project, "git merge" however
happily creates such a merge without any sign of something unusual
is happening.
Teach "git merge" to refuse to create such a merge by default,
unless the user passes a new "--allow-unrelated-histories" option to
tell it that the user is aware that two unrelated projects are
merged.
Because such a "two project merge" is a rare event, a configuration
option to always allow such a merge is not added.
We could add the same option to "git pull" and have it passed
through to underlying "git merge". I do not have a fundamental
opposition against such a feature, but this commit does not do so
and instead leaves it as low-hanging fruit for others, because such
a "two project merge" would be done after fetching the other project
into some location in the working tree of an existing project and
making sure how well they fit together, it is sufficient to allow a
local merge without such an option pass-through from "git pull" to
"git merge". Many tests that are updated by this patch does the
pass-through manually by turning:
git pull something
into its equivalent:
git fetch something &&
git merge --allow-unrelated-histories FETCH_HEAD
If somebody is inclined to add such an option, updated tests in this
change need to be adjusted back to:
git pull --allow-unrelated-histories something
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-18 20:21:09 +00:00
|
|
|
OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories,
|
|
|
|
N_("allow merging unrelated histories")),
|
2012-08-20 12:32:24 +00:00
|
|
|
OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
|
2014-03-23 22:58:12 +00:00
|
|
|
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
|
2012-08-20 12:32:24 +00:00
|
|
|
N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
|
2020-04-07 14:28:07 +00:00
|
|
|
OPT_AUTOSTASH(&autostash),
|
2013-08-03 11:51:19 +00:00
|
|
|
OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
|
Documentation: stylistically normalize references to Signed-off-by:
Ted reported an old typo in the git-commit.txt and merge-options.txt.
Namely, the phrase "Signed-off-by line" was used without either a
definite nor indefinite article.
Upon examination, it seems that the documentation (including items in
Documentation/, but also option help strings) have been quite
inconsistent on usage when referring to `Signed-off-by`.
First, very few places used a definite or indefinite article with the
phrase "Signed-off-by line", but that was the initial typo that led
to this investigation. So, normalize using either an indefinite or
definite article consistently.
The original phrasing, in Commit 3f971fc425b (Documentation updates,
2005-08-14), is "Add Signed-off-by line". Commit 6f855371a53 (Add
--signoff, --check, and long option-names. 2005-12-09) switched to
using "Add `Signed-off-by:` line", but didn't normalize the former
commit to match. Later commits seem to have cut and pasted from one
or the other, which is likely how the usage became so inconsistent.
Junio stated on the git mailing list in
<xmqqy2k1dfoh.fsf@gitster.c.googlers.com> a preference to leave off
the colon. Thus, prefer `Signed-off-by` (with backticks) for the
documentation files and Signed-off-by (without backticks) for option
help strings.
Additionally, Junio argued that "trailer" is now the standard term to
refer to `Signed-off-by`, saying that "becomes plenty clear that we
are not talking about any random line in the log message". As such,
prefer "trailer" over "line" anywhere the former word fits.
However, leave alone those few places in documentation that use
Signed-off-by to refer to the process (rather than the specific
trailer), or in places where mail headers are generally discussed in
comparison with Signed-off-by.
Reported-by: "Theodore Y. Ts'o" <tytso@mit.edu>
Signed-off-by: Bradley M. Kuhn <bkuhn@sfconservancy.org>
Acked-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-10-20 01:03:55 +00:00
|
|
|
OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),
|
2019-08-07 18:57:08 +00:00
|
|
|
OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
|
2008-07-07 17:24:20 +00:00
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
static int save_state(struct object_id *stash)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
|
|
|
int len;
|
2014-08-19 19:09:35 +00:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
struct strbuf buffer = STRBUF_INIT;
|
2022-07-23 01:53:15 +00:00
|
|
|
struct lock_file lock_file = LOCK_INIT;
|
|
|
|
int fd;
|
2017-08-30 17:49:49 +00:00
|
|
|
int rc = -1;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2022-07-23 01:53:15 +00:00
|
|
|
fd = repo_hold_locked_index(the_repository, &lock_file, 0);
|
2022-11-19 13:07:38 +00:00
|
|
|
refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
|
2022-07-23 01:53:15 +00:00
|
|
|
if (0 <= fd)
|
|
|
|
repo_update_index_if_able(the_repository, &lock_file);
|
|
|
|
rollback_lock_file(&lock_file);
|
|
|
|
|
2021-11-25 22:52:20 +00:00
|
|
|
strvec_pushl(&cp.args, "stash", "create", NULL);
|
2008-07-07 17:24:20 +00:00
|
|
|
cp.out = -1;
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
|
|
|
|
if (start_command(&cp))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("could not run stash."));
|
2008-07-07 17:24:20 +00:00
|
|
|
len = strbuf_read(&buffer, cp.out, 1024);
|
|
|
|
close(cp.out);
|
|
|
|
|
|
|
|
if (finish_command(&cp) || len < 0)
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("stash failed"));
|
2011-08-19 14:50:05 +00:00
|
|
|
else if (!len) /* no changes */
|
2017-08-30 17:49:49 +00:00
|
|
|
goto out;
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_setlen(&buffer, buffer.len-1);
|
2023-03-28 13:58:46 +00:00
|
|
|
if (repo_get_oid(the_repository, buffer.buf, stash))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("not a valid object: %s"), buffer.buf);
|
2017-08-30 17:49:49 +00:00
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
strbuf_release(&buffer);
|
|
|
|
return rc;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2022-10-30 11:42:59 +00:00
|
|
|
static void read_empty(const struct object_id *oid)
|
2010-11-14 22:07:49 +00:00
|
|
|
{
|
2022-10-30 11:50:27 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2010-11-14 22:07:49 +00:00
|
|
|
|
2022-10-30 11:50:27 +00:00
|
|
|
strvec_pushl(&cmd.args, "read-tree", "-m", "-u", empty_tree_oid_hex(),
|
|
|
|
oid_to_hex(oid), NULL);
|
|
|
|
cmd.git_cmd = 1;
|
2010-11-14 22:07:49 +00:00
|
|
|
|
2022-10-30 11:50:27 +00:00
|
|
|
if (run_command(&cmd))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("read-tree failed"));
|
2010-11-14 22:07:49 +00:00
|
|
|
}
|
|
|
|
|
2022-10-30 11:42:59 +00:00
|
|
|
static void reset_hard(const struct object_id *oid)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2022-10-30 11:50:27 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2022-10-30 11:50:27 +00:00
|
|
|
strvec_pushl(&cmd.args, "read-tree", "-v", "--reset", "-u",
|
|
|
|
oid_to_hex(oid), NULL);
|
|
|
|
cmd.git_cmd = 1;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2022-10-30 11:50:27 +00:00
|
|
|
if (run_command(&cmd))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("read-tree failed"));
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
static void restore_state(const struct object_id *head,
|
|
|
|
const struct object_id *stash)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2022-10-30 11:51:14 +00:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2022-10-30 11:42:59 +00:00
|
|
|
reset_hard(head);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
merge: do not exit restore_state() prematurely
Previously, if the user:
* Had no local changes before starting the merge
* A merge strategy makes changes to the working tree/index but returns
with exit status 2
Then we'd call restore_state() to clean up the changes and either let
the next merge strategy run (if there is one), or exit telling the user
that no merge strategy could handle the merge. Unfortunately,
restore_state() did not clean up the changes as expected; that function
was a no-op if the stash was a null, and the stash would be null if
there were no local changes before starting the merge. So, instead of
"Rewinding the tree to pristine..." as the code claimed, restore_state()
would leave garbage around in the index and working tree (possibly
including conflicts) for either the next merge strategy or for the user
after aborting the merge. And in the case of aborting the merge, the
user would be unable to run "git merge --abort" to get rid of the
unintended leftover conflicts, because the merge control files were not
written as it was presumed that we had restored to a clean state
already.
Fix the main problem by making sure that restore_state() only skips the
stash application if the stash is null rather than skipping the whole
function.
However, there is a secondary problem -- since merge.c forks
subprocesses to do the cleanup, the in-memory index is left out-of-sync.
While there was a refresh_cache(REFRESH_QUIET) call that attempted to
correct that, that function would not handle cases where the previous
merge strategy added conflicted entries. We need to drop the index and
re-read it to handle such cases.
(Alternatively, we could stop forking subprocesses and instead call some
appropriate function to do the work which would update the in-memory
index automatically. For now, just do the simple fix.)
Also, add a testcase checking this, one for which the octopus strategy
fails on the first commit it attempts to merge, and thus which it
cannot handle at all and must completely bail on (as per the "exit 2"
code path of commit 98efc8f3d8 ("octopus: allow manual resolve on the
last round.", 2006-01-13)).
Reported-by: ZheNing Hu <adlternative@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:53:18 +00:00
|
|
|
if (is_null_oid(stash))
|
|
|
|
goto refresh_cache;
|
|
|
|
|
2022-10-30 11:51:14 +00:00
|
|
|
strvec_pushl(&cmd.args, "stash", "apply", "--index", "--quiet", NULL);
|
|
|
|
strvec_push(&cmd.args, oid_to_hex(stash));
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It is OK to ignore error here, for example when there was
|
|
|
|
* nothing to restore.
|
|
|
|
*/
|
2022-10-30 11:51:14 +00:00
|
|
|
cmd.git_cmd = 1;
|
|
|
|
run_command(&cmd);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
merge: do not exit restore_state() prematurely
Previously, if the user:
* Had no local changes before starting the merge
* A merge strategy makes changes to the working tree/index but returns
with exit status 2
Then we'd call restore_state() to clean up the changes and either let
the next merge strategy run (if there is one), or exit telling the user
that no merge strategy could handle the merge. Unfortunately,
restore_state() did not clean up the changes as expected; that function
was a no-op if the stash was a null, and the stash would be null if
there were no local changes before starting the merge. So, instead of
"Rewinding the tree to pristine..." as the code claimed, restore_state()
would leave garbage around in the index and working tree (possibly
including conflicts) for either the next merge strategy or for the user
after aborting the merge. And in the case of aborting the merge, the
user would be unable to run "git merge --abort" to get rid of the
unintended leftover conflicts, because the merge control files were not
written as it was presumed that we had restored to a clean state
already.
Fix the main problem by making sure that restore_state() only skips the
stash application if the stash is null rather than skipping the whole
function.
However, there is a secondary problem -- since merge.c forks
subprocesses to do the cleanup, the in-memory index is left out-of-sync.
While there was a refresh_cache(REFRESH_QUIET) call that attempted to
correct that, that function would not handle cases where the previous
merge strategy added conflicted entries. We need to drop the index and
re-read it to handle such cases.
(Alternatively, we could stop forking subprocesses and instead call some
appropriate function to do the work which would update the in-memory
index automatically. For now, just do the simple fix.)
Also, add a testcase checking this, one for which the octopus strategy
fails on the first commit it attempts to merge, and thus which it
cannot handle at all and must completely bail on (as per the "exit 2"
code path of commit 98efc8f3d8 ("octopus: allow manual resolve on the
last round.", 2006-01-13)).
Reported-by: ZheNing Hu <adlternative@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:53:18 +00:00
|
|
|
refresh_cache:
|
2023-02-10 10:28:39 +00:00
|
|
|
discard_index(&the_index);
|
|
|
|
if (repo_read_index(the_repository) < 0)
|
merge: do not exit restore_state() prematurely
Previously, if the user:
* Had no local changes before starting the merge
* A merge strategy makes changes to the working tree/index but returns
with exit status 2
Then we'd call restore_state() to clean up the changes and either let
the next merge strategy run (if there is one), or exit telling the user
that no merge strategy could handle the merge. Unfortunately,
restore_state() did not clean up the changes as expected; that function
was a no-op if the stash was a null, and the stash would be null if
there were no local changes before starting the merge. So, instead of
"Rewinding the tree to pristine..." as the code claimed, restore_state()
would leave garbage around in the index and working tree (possibly
including conflicts) for either the next merge strategy or for the user
after aborting the merge. And in the case of aborting the merge, the
user would be unable to run "git merge --abort" to get rid of the
unintended leftover conflicts, because the merge control files were not
written as it was presumed that we had restored to a clean state
already.
Fix the main problem by making sure that restore_state() only skips the
stash application if the stash is null rather than skipping the whole
function.
However, there is a secondary problem -- since merge.c forks
subprocesses to do the cleanup, the in-memory index is left out-of-sync.
While there was a refresh_cache(REFRESH_QUIET) call that attempted to
correct that, that function would not handle cases where the previous
merge strategy added conflicted entries. We need to drop the index and
re-read it to handle such cases.
(Alternatively, we could stop forking subprocesses and instead call some
appropriate function to do the work which would update the in-memory
index automatically. For now, just do the simple fix.)
Also, add a testcase checking this, one for which the octopus strategy
fails on the first commit it attempts to merge, and thus which it
cannot handle at all and must completely bail on (as per the "exit 2"
code path of commit 98efc8f3d8 ("octopus: allow manual resolve on the
last round.", 2006-01-13)).
Reported-by: ZheNing Hu <adlternative@gmail.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:53:18 +00:00
|
|
|
die(_("could not read index"));
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This is called when no merge was necessary. */
|
2021-05-02 05:14:23 +00:00
|
|
|
static void finish_up_to_date(void)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2021-05-02 05:14:23 +00:00
|
|
|
if (verbosity >= 0) {
|
|
|
|
if (squash)
|
|
|
|
puts(_("Already up to date. (nothing to squash)"));
|
|
|
|
else
|
|
|
|
puts(_("Already up to date."));
|
|
|
|
}
|
2019-05-09 10:10:27 +00:00
|
|
|
remove_merge_branch_state(the_repository);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 23:15:13 +00:00
|
|
|
static void squash_message(struct commit *commit, struct commit_list *remoteheads)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
|
|
|
struct rev_info rev;
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf out = STRBUF_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
struct commit_list *j;
|
2009-10-19 15:48:08 +00:00
|
|
|
struct pretty_print_context ctx = {0};
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Squash commit -- not updating HEAD\n"));
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2018-09-21 15:57:38 +00:00
|
|
|
repo_init_revisions(the_repository, &rev, NULL);
|
2020-12-21 15:19:38 +00:00
|
|
|
diff_merges_suppress(&rev);
|
2008-07-07 17:24:20 +00:00
|
|
|
rev.commit_format = CMIT_FMT_MEDIUM;
|
|
|
|
|
|
|
|
commit->object.flags |= UNINTERESTING;
|
|
|
|
add_pending_object(&rev, &commit->object, NULL);
|
|
|
|
|
|
|
|
for (j = remoteheads; j; j = j->next)
|
|
|
|
add_pending_object(&rev, &j->item->object, NULL);
|
|
|
|
|
|
|
|
setup_revisions(0, NULL, &rev, NULL);
|
|
|
|
if (prepare_revision_walk(&rev))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("revision walk setup failed"));
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2009-10-19 15:48:08 +00:00
|
|
|
ctx.abbrev = rev.abbrev;
|
|
|
|
ctx.date_mode = rev.date_mode;
|
2011-05-26 22:27:49 +00:00
|
|
|
ctx.fmt = rev.commit_format;
|
2009-10-19 15:48:08 +00:00
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_addstr(&out, "Squashed commit of the following:\n");
|
|
|
|
while ((commit = get_revision(&rev)) != NULL) {
|
|
|
|
strbuf_addch(&out, '\n');
|
|
|
|
strbuf_addf(&out, "commit %s\n",
|
2015-11-10 02:22:28 +00:00
|
|
|
oid_to_hex(&commit->object.oid));
|
2011-05-26 22:27:49 +00:00
|
|
|
pretty_print_commit(&ctx, commit, &out);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
2018-05-17 22:51:51 +00:00
|
|
|
write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_release(&out);
|
2022-04-13 20:01:36 +00:00
|
|
|
release_revisions(&rev);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2011-09-17 11:57:44 +00:00
|
|
|
static void finish(struct commit *head_commit,
|
2012-04-16 23:15:13 +00:00
|
|
|
struct commit_list *remoteheads,
|
2017-02-21 23:47:28 +00:00
|
|
|
const struct object_id *new_head, const char *msg)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf reflog_message = STRBUF_INIT;
|
2017-02-21 23:47:28 +00:00
|
|
|
const struct object_id *head = &head_commit->object.oid;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
if (!msg)
|
|
|
|
strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
|
|
|
|
else {
|
2008-11-15 00:14:24 +00:00
|
|
|
if (verbosity >= 0)
|
|
|
|
printf("%s\n", msg);
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_addf(&reflog_message, "%s: %s",
|
|
|
|
getenv("GIT_REFLOG_ACTION"), msg);
|
|
|
|
}
|
|
|
|
if (squash) {
|
2012-04-16 23:15:13 +00:00
|
|
|
squash_message(head_commit, remoteheads);
|
2008-07-07 17:24:20 +00:00
|
|
|
} else {
|
2008-11-15 00:14:24 +00:00
|
|
|
if (verbosity >= 0 && !merge_msg.len)
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("No merge message -- not updating HEAD\n"));
|
2008-07-07 17:24:20 +00:00
|
|
|
else {
|
2017-10-15 22:06:51 +00:00
|
|
|
update_ref(reflog_message.buf, "HEAD", new_head, head,
|
|
|
|
0, UPDATE_REFS_DIE_ON_ERR);
|
2008-07-07 17:24:20 +00:00
|
|
|
/*
|
|
|
|
* We ignore errors in 'gc --auto', since the
|
|
|
|
* user should see them.
|
|
|
|
*/
|
2020-09-17 18:11:44 +00:00
|
|
|
run_auto_maintenance(verbosity < 0);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (new_head && show_diffstat) {
|
|
|
|
struct diff_options opts;
|
2018-09-21 15:57:24 +00:00
|
|
|
repo_diff_setup(the_repository, &opts);
|
2012-03-01 12:26:42 +00:00
|
|
|
opts.stat_width = -1; /* use full terminal width */
|
2012-03-01 12:26:46 +00:00
|
|
|
opts.stat_graph_width = -1; /* respect statGraphWidth config */
|
2008-07-07 17:24:20 +00:00
|
|
|
opts.output_format |=
|
|
|
|
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
|
|
|
|
opts.detect_rename = DIFF_DETECT_RENAME;
|
2012-08-03 12:16:24 +00:00
|
|
|
diff_setup_done(&opts);
|
2017-05-30 17:31:03 +00:00
|
|
|
diff_tree_oid(head, new_head, "", &opts);
|
2008-07-07 17:24:20 +00:00
|
|
|
diffcore_std(&opts);
|
|
|
|
diff_flush(&opts);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Run a post-merge hook */
|
2021-12-22 03:59:34 +00:00
|
|
|
run_hooks_l("post-merge", squash ? "1" : "0", NULL);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2022-08-23 02:42:19 +00:00
|
|
|
if (new_head)
|
|
|
|
apply_autostash(git_path_merge_autostash(the_repository));
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_release(&reflog_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the name for the merge commit's message. */
|
|
|
|
static void merge_name(const char *remote, struct strbuf *msg)
|
|
|
|
{
|
2011-11-07 21:26:22 +00:00
|
|
|
struct commit *remote_head;
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id branch_head;
|
2009-02-14 07:26:12 +00:00
|
|
|
struct strbuf bname = STRBUF_INIT;
|
2018-05-19 05:28:30 +00:00
|
|
|
struct merge_remote_desc *desc;
|
2008-07-07 17:24:20 +00:00
|
|
|
const char *ptr;
|
2021-07-25 13:08:28 +00:00
|
|
|
char *found_ref = NULL;
|
2008-07-07 17:24:20 +00:00
|
|
|
int len, early;
|
|
|
|
|
interpret_branch_name: allow callers to restrict expansions
The interpret_branch_name() function converts names like
@{-1} and @{upstream} into branch names. The expanded ref
names are not fully qualified, and may be outside of the
refs/heads/ namespace (e.g., "@" expands to "HEAD", and
"@{upstream}" is likely to be in "refs/remotes/").
This is OK for callers like dwim_ref() which are primarily
interested in resolving the resulting name, no matter where
it is. But callers like "git branch" treat the result as a
branch name in refs/heads/. When we expand to a ref outside
that namespace, the results are very confusing (e.g., "git
branch @" tries to create refs/heads/HEAD, which is
nonsense).
Callers can't know from the returned string how the
expansion happened (e.g., did the user really ask for a
branch named "HEAD", or did we do a bogus expansion?). One
fix would be to return some out-parameters describing the
types of expansion that occurred. This has the benefit that
the caller can generate precise error messages ("I
understood @{upstream} to mean origin/master, but that is a
remote tracking branch, so you cannot create it as a local
name").
However, out-parameters make the function interface somewhat
cumbersome. Instead, let's do the opposite: let the caller
tell us which elements to expand. That's easier to pass in,
and none of the callers give more precise error messages
than "@{upstream} isn't a valid branch name" anyway (which
should be sufficient).
The strbuf_branchname() function needs a similar parameter,
as most of the callers access interpret_branch_name()
through it.
We can break the callers down into two groups:
1. Callers that are happy with any kind of ref in the
result. We pass "0" here, so they continue to work
without restrictions. This includes merge_name(),
the reflog handling in add_pending_object_with_path(),
and substitute_branch_name(). This last is what powers
dwim_ref().
2. Callers that have funny corner cases (mostly in
git-branch and git-checkout). These need to make use of
the new parameter, but I've left them as "0" in this
patch, and will address them individually in follow-on
patches.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-02 08:23:01 +00:00
|
|
|
strbuf_branchname(&bname, remote, 0);
|
2009-03-21 20:17:30 +00:00
|
|
|
remote = bname.buf;
|
2009-02-14 07:26:12 +00:00
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
oidclr(&branch_head);
|
2011-11-07 21:26:22 +00:00
|
|
|
remote_head = get_merge_parent(remote);
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!remote_head)
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("'%s' does not point to a commit"), remote);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2023-03-28 13:58:54 +00:00
|
|
|
if (repo_dwim_ref(the_repository, remote, strlen(remote), &branch_head,
|
|
|
|
&found_ref, 0) > 0) {
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(found_ref, "refs/heads/")) {
|
merge: fix incorrect merge message for ambiguous tag/branch
If we have both a tag and a branch named "foo", then calling
"git merge foo" will warn about the ambiguous ref, but merge
the tag.
When generating the commit message, though, we simply
checked whether "refs/heads/foo" existed, and if it did,
assumed it was a branch. This led to the statement "Merge
branch 'foo'" in the commit message, which is quite wrong.
Instead, we should use dwim_ref to find the actual ref used,
and describe it appropriately.
In addition to the test in t7608, we must also tweak the
expected output of t4202, which was accidentally triggering
this bug.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-09 10:02:24 +00:00
|
|
|
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
|
2017-02-21 23:47:28 +00:00
|
|
|
oid_to_hex(&branch_head), remote);
|
merge: fix incorrect merge message for ambiguous tag/branch
If we have both a tag and a branch named "foo", then calling
"git merge foo" will warn about the ambiguous ref, but merge
the tag.
When generating the commit message, though, we simply
checked whether "refs/heads/foo" existed, and if it did,
assumed it was a branch. This led to the statement "Merge
branch 'foo'" in the commit message, which is quite wrong.
Instead, we should use dwim_ref to find the actual ref used,
and describe it appropriately.
In addition to the test in t7608, we must also tweak the
expected output of t4202, which was accidentally triggering
this bug.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-08-09 10:02:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(found_ref, "refs/tags/")) {
|
2011-11-05 04:31:28 +00:00
|
|
|
strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
|
2017-02-21 23:47:28 +00:00
|
|
|
oid_to_hex(&branch_head), remote);
|
2011-11-05 04:31:28 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-11-30 20:55:40 +00:00
|
|
|
if (starts_with(found_ref, "refs/remotes/")) {
|
2010-11-02 15:31:25 +00:00
|
|
|
strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
|
2017-02-21 23:47:28 +00:00
|
|
|
oid_to_hex(&branch_head), remote);
|
2009-08-09 10:02:51 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* See if remote matches <name>^^^.. or <name>~<number> */
|
|
|
|
for (len = 0, ptr = remote + strlen(remote);
|
|
|
|
remote < ptr && ptr[-1] == '^';
|
|
|
|
ptr--)
|
|
|
|
len++;
|
|
|
|
if (len)
|
|
|
|
early = 1;
|
|
|
|
else {
|
|
|
|
early = 0;
|
|
|
|
ptr = strrchr(remote, '~');
|
|
|
|
if (ptr) {
|
|
|
|
int seen_nonzero = 0;
|
|
|
|
|
|
|
|
len++; /* count ~ */
|
|
|
|
while (*++ptr && isdigit(*ptr)) {
|
|
|
|
seen_nonzero |= (*ptr != '0');
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
if (*ptr)
|
|
|
|
len = 0; /* not ...~<number> */
|
|
|
|
else if (seen_nonzero)
|
|
|
|
early = 1;
|
|
|
|
else if (len == 1)
|
|
|
|
early = 1; /* "name~" is "name~1"! */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (len) {
|
|
|
|
struct strbuf truname = STRBUF_INIT;
|
2015-04-23 21:37:13 +00:00
|
|
|
strbuf_addf(&truname, "refs/heads/%s", remote);
|
Fix merge name generation in "merge in C"
When merging an early part of a branch, e.g. "git merge xyzzy~20", we were
supposed to say "branch 'xyzzy' (early part)", but it incorrectly said
"branch 'refs/heads/xy' (early part)" instead.
The logic was supposed to first strip away "~20" part to make sure that
what follows "~" is a non-zero posint, prefix it with "refs/heads/" and
ask resolve_ref() if it is a ref. If it is, then we know xyzzy was a
branch, and we can give the correct message.
However, there were a few bugs. First of all, the logic to build this
"true branch refname" did not count the characters correctly. At this
point of the code, "len" is the number of trailing, non-name part of the
given extended SHA-1 expression given by the user, i.e. number of bytes in
"~20" in the above example.
In addition, the message forgot to skip "refs/heads/" it prefixed from the
output.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-30 08:12:19 +00:00
|
|
|
strbuf_setlen(&truname, truname.len - len);
|
2011-11-13 10:22:14 +00:00
|
|
|
if (ref_exists(truname.buf)) {
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_addf(msg,
|
|
|
|
"%s\t\tbranch '%s'%s of .\n",
|
2016-06-24 23:09:22 +00:00
|
|
|
oid_to_hex(&remote_head->object.oid),
|
Fix merge name generation in "merge in C"
When merging an early part of a branch, e.g. "git merge xyzzy~20", we were
supposed to say "branch 'xyzzy' (early part)", but it incorrectly said
"branch 'refs/heads/xy' (early part)" instead.
The logic was supposed to first strip away "~20" part to make sure that
what follows "~" is a non-zero posint, prefix it with "refs/heads/" and
ask resolve_ref() if it is a ref. If it is, then we know xyzzy was a
branch, and we can give the correct message.
However, there were a few bugs. First of all, the logic to build this
"true branch refname" did not count the characters correctly. At this
point of the code, "len" is the number of trailing, non-name part of the
given extended SHA-1 expression given by the user, i.e. number of bytes in
"~20" in the above example.
In addition, the message forgot to skip "refs/heads/" it prefixed from the
output.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-30 08:12:19 +00:00
|
|
|
truname.buf + 11,
|
2008-07-07 17:24:20 +00:00
|
|
|
(early ? " (early part)" : ""));
|
2009-02-14 07:26:12 +00:00
|
|
|
strbuf_release(&truname);
|
|
|
|
goto cleanup;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
2015-04-23 21:37:13 +00:00
|
|
|
strbuf_release(&truname);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
2013-03-19 16:55:34 +00:00
|
|
|
|
2018-05-19 05:28:30 +00:00
|
|
|
desc = merge_remote_util(remote_head);
|
|
|
|
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
|
|
|
|
strbuf_addf(msg, "%s\t\t%s '%s'\n",
|
|
|
|
oid_to_hex(&desc->obj->oid),
|
|
|
|
type_name(desc->obj->type),
|
|
|
|
remote);
|
|
|
|
goto cleanup;
|
2013-03-19 16:55:34 +00:00
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
|
2016-06-24 23:09:22 +00:00
|
|
|
oid_to_hex(&remote_head->object.oid), remote);
|
2009-02-14 07:26:12 +00:00
|
|
|
cleanup:
|
2021-07-25 13:08:28 +00:00
|
|
|
free(found_ref);
|
2009-02-14 07:26:12 +00:00
|
|
|
strbuf_release(&bname);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 00:42:51 +00:00
|
|
|
static void parse_branch_merge_options(char *bmo)
|
|
|
|
{
|
|
|
|
const char **argv;
|
|
|
|
int argc;
|
|
|
|
|
|
|
|
if (!bmo)
|
|
|
|
return;
|
|
|
|
argc = split_cmdline(bmo, &argv);
|
|
|
|
if (argc < 0)
|
2011-05-11 18:38:36 +00:00
|
|
|
die(_("Bad branch.%s.mergeoptions string: %s"), branch,
|
2018-11-10 05:16:01 +00:00
|
|
|
_(split_cmdline_strerror(argc)));
|
2014-09-16 18:56:57 +00:00
|
|
|
REALLOC_ARRAY(argv, argc + 2);
|
2017-07-15 20:00:45 +00:00
|
|
|
MOVE_ARRAY(argv + 1, argv, argc + 1);
|
2011-05-05 00:42:51 +00:00
|
|
|
argc++;
|
|
|
|
argv[0] = "branch.*.mergeoptions";
|
|
|
|
parse_options(argc, argv, NULL, builtin_merge_options,
|
|
|
|
builtin_merge_usage, 0);
|
|
|
|
free(argv);
|
|
|
|
}
|
|
|
|
|
2008-07-23 23:09:35 +00:00
|
|
|
static int git_merge_config(const char *k, const char *v, void *cb)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2011-10-07 06:12:09 +00:00
|
|
|
int status;
|
2020-04-11 07:11:45 +00:00
|
|
|
const char *str;
|
2011-10-07 06:12:09 +00:00
|
|
|
|
2020-04-11 07:11:45 +00:00
|
|
|
if (branch &&
|
|
|
|
skip_prefix(k, "branch.", &str) &&
|
|
|
|
skip_prefix(str, branch, &str) &&
|
|
|
|
!strcmp(str, ".mergeoptions")) {
|
2011-05-05 00:42:51 +00:00
|
|
|
free(branch_mergeoptions);
|
|
|
|
branch_mergeoptions = xstrdup(v);
|
|
|
|
return 0;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
|
|
|
|
show_diffstat = git_config_bool(k, v);
|
2017-12-10 06:53:57 +00:00
|
|
|
else if (!strcmp(k, "merge.verifysignatures"))
|
|
|
|
verify_signatures = git_config_bool(k, v);
|
2008-07-07 17:24:20 +00:00
|
|
|
else if (!strcmp(k, "pull.twohead"))
|
|
|
|
return git_config_string(&pull_twohead, k, v);
|
|
|
|
else if (!strcmp(k, "pull.octopus"))
|
|
|
|
return git_config_string(&pull_octopus, k, v);
|
2019-04-17 10:23:27 +00:00
|
|
|
else if (!strcmp(k, "commit.cleanup"))
|
|
|
|
return git_config_string(&cleanup_arg, k, v);
|
2011-10-07 06:12:09 +00:00
|
|
|
else if (!strcmp(k, "merge.ff")) {
|
2017-08-07 18:20:49 +00:00
|
|
|
int boolval = git_parse_maybe_bool(v);
|
2011-05-06 19:27:05 +00:00
|
|
|
if (0 <= boolval) {
|
2013-07-02 14:47:57 +00:00
|
|
|
fast_forward = boolval ? FF_ALLOW : FF_NO;
|
2011-05-06 19:27:05 +00:00
|
|
|
} else if (v && !strcmp(v, "only")) {
|
2013-07-02 14:47:57 +00:00
|
|
|
fast_forward = FF_ONLY;
|
2011-05-06 19:27:05 +00:00
|
|
|
} /* do not barf on values from future versions of git */
|
|
|
|
return 0;
|
2011-03-24 06:48:24 +00:00
|
|
|
} else if (!strcmp(k, "merge.defaulttoupstream")) {
|
|
|
|
default_to_upstream = git_config_bool(k, v);
|
|
|
|
return 0;
|
2013-11-04 23:14:41 +00:00
|
|
|
} else if (!strcmp(k, "commit.gpgsign")) {
|
|
|
|
sign_commit = git_config_bool(k, v) ? "" : NULL;
|
|
|
|
return 0;
|
gpg-interface: add minTrustLevel as a configuration option
Previously, signature verification for merge and pull operations checked
if the key had a trust-level of either TRUST_NEVER or TRUST_UNDEFINED in
verify_merge_signature(). If that was the case, the process die()d.
The other code paths that did signature verification relied entirely on
the return code from check_commit_signature(). And signatures made with
a good key, irregardless of its trust level, was considered valid by
check_commit_signature().
This difference in behavior might induce users to erroneously assume
that the trust level of a key in their keyring is always considered by
Git, even for operations where it is not (e.g. during a verify-commit or
verify-tag).
The way it worked was by gpg-interface.c storing the result from the
key/signature status *and* the lowest-two trust levels in the `result`
member of the signature_check structure (the last of these status lines
that were encountered got written to `result`). These are documented in
GPG under the subsection `General status codes` and `Key related`,
respectively [1].
The GPG documentation says the following on the TRUST_ status codes [1]:
"""
These are several similar status codes:
- TRUST_UNDEFINED <error_token>
- TRUST_NEVER <error_token>
- TRUST_MARGINAL [0 [<validation_model>]]
- TRUST_FULLY [0 [<validation_model>]]
- TRUST_ULTIMATE [0 [<validation_model>]]
For good signatures one of these status lines are emitted to
indicate the validity of the key used to create the signature.
The error token values are currently only emitted by gpgsm.
"""
My interpretation is that the trust level is conceptionally different
from the validity of the key and/or signature. That seems to also have
been the assumption of the old code in check_signature() where a result
of 'G' (as in GOODSIG) and 'U' (as in TRUST_NEVER or TRUST_UNDEFINED)
were both considered a success.
The two cases where a result of 'U' had special meaning were in
verify_merge_signature() (where this caused git to die()) and in
format_commit_one() (where it affected the output of the %G? format
specifier).
I think it makes sense to refactor the processing of TRUST_ status lines
such that users can configure a minimum trust level that is enforced
globally, rather than have individual parts of git (e.g. merge) do it
themselves (except for a grace period with backward compatibility).
I also think it makes sense to not store the trust level in the same
struct member as the key/signature status. While the presence of a
TRUST_ status code does imply that the signature is good (see the first
paragraph in the included snippet above), as far as I can tell, the
order of the status lines from GPG isn't well-defined; thus it would
seem plausible that the trust level could be overwritten with the
key/signature status if they were stored in the same member of the
signature_check structure.
This patch introduces a new configuration option: gpg.minTrustLevel. It
consolidates trust-level verification to gpg-interface.c and adds a new
`trust_level` member to the signature_check structure.
Backward-compatibility is maintained by introducing a special case in
verify_merge_signature() such that if no user-configurable
gpg.minTrustLevel is set, then the old behavior of rejecting
TRUST_UNDEFINED and TRUST_NEVER is enforced. If, on the other hand,
gpg.minTrustLevel is set, then that value overrides the old behavior.
Similarly, the %G? format specifier will continue show 'U' for
signatures made with a key that has a trust level of TRUST_UNDEFINED or
TRUST_NEVER, even though the 'U' character no longer exist in the
`result` member of the signature_check structure. A new format
specifier, %GT, is also introduced for users that want to show all
possible trust levels for a signature.
Another approach would have been to simply drop the trust-level
requirement in verify_merge_signature(). This would also have made the
behavior consistent with other parts of git that perform signature
verification. However, requiring a minimum trust level for signing keys
does seem to have a real-world use-case. For example, the build system
used by the Qubes OS project currently parses the raw output from
verify-tag in order to assert a minimum trust level for keys used to
sign git tags [2].
[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/doc/DETAILS;h=bd00006e933ac56719b1edd2478ecd79273eae72;hb=refs/heads/master
[2] https://github.com/QubesOS/qubes-builder/blob/9674c1991deef45b1a1b1c71fddfab14ba50dccf/scripts/verify-git-tag#L43
Signed-off-by: Hans Jerry Illikainen <hji@dyntopia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-27 13:55:57 +00:00
|
|
|
} else if (!strcmp(k, "gpg.mintrustlevel")) {
|
|
|
|
check_trust_level = 0;
|
2020-04-07 14:28:07 +00:00
|
|
|
} else if (!strcmp(k, "merge.autostash")) {
|
|
|
|
autostash = git_config_bool(k, v);
|
|
|
|
return 0;
|
2010-09-08 17:59:54 +00:00
|
|
|
}
|
commit: teach --gpg-sign option
This uses the gpg-interface.[ch] to allow signing the commit, i.e.
$ git commit --gpg-sign -m foo
You need a passphrase to unlock the secret key for
user: "Junio C Hamano <gitster@pobox.com>"
4096-bit RSA key, ID 96AFE6CB, created 2011-10-03 (main key ID 713660A7)
[master 8457d13] foo
1 files changed, 1 insertions(+), 0 deletions(-)
The lines of GPG detached signature are placed in a new multi-line header
field, instead of tucking the signature block at the end of the commit log
message text (similar to how signed tag is done), for multiple reasons:
- The signature won't clutter output from "git log" and friends if it is
in the extra header. If we place it at the end of the log message, we
would need to teach "git log" and friends to strip the signature block
with an option.
- Teaching new versions of "git log" and "gitk" to optionally verify and
show signatures is cleaner if we structurally know where the signature
block is (instead of scanning in the commit log message).
- The signature needs to be stripped upon various commit rewriting
operations, e.g. rebase, filter-branch, etc. They all already ignore
unknown headers, but if we place signature in the log message, all of
these tools (and third-party tools) also need to learn how a signature
block would look like.
- When we added the optional encoding header, all the tools (both in tree
and third-party) that acts on the raw commit object should have been
fixed to ignore headers they do not understand, so it is not like that
new header would be more likely to break than extra text in the commit.
A commit made with the above sample sequence would look like this:
$ git cat-file commit HEAD
tree 3cd71d90e3db4136e5260ab54599791c4f883b9d
parent b87755351a47b09cb27d6913e6e0e17e6254a4d4
author Junio C Hamano <gitster@pobox.com> 1317862251 -0700
committer Junio C Hamano <gitster@pobox.com> 1317862251 -0700
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
iQIcBAABAgAGBQJOjPtrAAoJELC16IaWr+bL4TMP/RSe2Y/jYnCkds9unO5JEnfG
...
=dt98
-----END PGP SIGNATURE-----
foo
but "git log" (unless you ask for it with --pretty=raw) output is not
cluttered with the signature information.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-06 00:23:20 +00:00
|
|
|
|
2011-10-07 06:12:09 +00:00
|
|
|
status = fmt_merge_msg_config(k, v, cb);
|
|
|
|
if (status)
|
|
|
|
return status;
|
2008-07-07 17:24:20 +00:00
|
|
|
return git_diff_ui_config(k, v, cb);
|
|
|
|
}
|
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
static int read_tree_trivial(struct object_id *common, struct object_id *head,
|
|
|
|
struct object_id *one)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
|
|
|
int i, nr_trees = 0;
|
|
|
|
struct tree *trees[MAX_UNPACK_TREES];
|
|
|
|
struct tree_desc t[MAX_UNPACK_TREES];
|
|
|
|
struct unpack_trees_options opts;
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
opts.head_idx = 2;
|
|
|
|
opts.src_index = &the_index;
|
|
|
|
opts.dst_index = &the_index;
|
|
|
|
opts.update = 1;
|
|
|
|
opts.verbose_update = 1;
|
|
|
|
opts.trivial_merges_only = 1;
|
|
|
|
opts.merge = 1;
|
2021-09-27 16:33:43 +00:00
|
|
|
opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
|
2017-05-06 22:10:37 +00:00
|
|
|
trees[nr_trees] = parse_tree_indirect(common);
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!trees[nr_trees++])
|
|
|
|
return -1;
|
2017-05-06 22:10:37 +00:00
|
|
|
trees[nr_trees] = parse_tree_indirect(head);
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!trees[nr_trees++])
|
|
|
|
return -1;
|
2017-05-06 22:10:37 +00:00
|
|
|
trees[nr_trees] = parse_tree_indirect(one);
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!trees[nr_trees++])
|
|
|
|
return -1;
|
|
|
|
opts.fn = threeway_merge;
|
2022-11-19 13:07:34 +00:00
|
|
|
cache_tree_free(&the_index.cache_tree);
|
2008-07-07 17:24:20 +00:00
|
|
|
for (i = 0; i < nr_trees; i++) {
|
|
|
|
parse_tree(trees[i]);
|
|
|
|
init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
|
|
|
|
}
|
|
|
|
if (unpack_trees(nr_trees, t, &opts))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
static void write_tree_trivial(struct object_id *oid)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
cocci & cache-tree.h: migrate "write_cache_as_tree" to "*_index_*"
Add a trivial rule for "write_cache_as_tree" to
"index-compatibility.cocci", and apply it. This was left out of the
rules added in 0e6550a2c63 (cocci: add a
index-compatibility.pending.cocci, 2022-11-19) because this
compatibility wrapper lived in "cache-tree.h", not "cache.h"
But it's like the other "USE_THE_INDEX_COMPATIBILITY_MACROS", so let's
migrate it too.
The replacement of "USE_THE_INDEX_COMPATIBILITY_MACROS" here with
"USE_THE_INDEX_VARIABLE" is a manual change on top, now that these
files only use "&the_index", and don't need any compatibility
macros (or functions).
The wrapping of some argument lists is likewise manual, as coccinelle
would otherwise give us overly long argument lists.
The reason for putting the "O" in the cocci rule on the "-" and "+"
lines is because I couldn't get correct whitespacing otherwise,
i.e. I'd end up with "oid,&the_index", not "oid, &the_index".
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-02-10 10:28:37 +00:00
|
|
|
if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("git write-tree failed to write a tree"));
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2010-03-31 19:22:06 +00:00
|
|
|
static int try_merge_strategy(const char *strategy, struct commit_list *common,
|
2012-04-16 23:15:13 +00:00
|
|
|
struct commit_list *remoteheads,
|
2015-03-26 05:00:48 +00:00
|
|
|
struct commit *head)
|
2010-03-31 19:22:06 +00:00
|
|
|
{
|
2015-03-26 05:00:48 +00:00
|
|
|
const char *head_arg = "HEAD";
|
2008-10-03 13:02:31 +00:00
|
|
|
|
2022-11-19 13:07:38 +00:00
|
|
|
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
|
|
|
|
SKIP_IF_UNCHANGED, 0, NULL, NULL,
|
|
|
|
NULL) < 0)
|
2011-02-22 23:41:59 +00:00
|
|
|
return error(_("Unable to write index."));
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2020-11-02 23:45:34 +00:00
|
|
|
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
|
|
|
|
!strcmp(strategy, "ort")) {
|
2019-09-11 18:20:26 +00:00
|
|
|
struct lock_file lock = LOCK_INIT;
|
2010-03-31 19:22:06 +00:00
|
|
|
int clean, x;
|
2008-08-28 13:43:00 +00:00
|
|
|
struct commit *result;
|
|
|
|
struct commit_list *reversed = NULL;
|
|
|
|
struct merge_options o;
|
2010-03-31 19:22:06 +00:00
|
|
|
struct commit_list *j;
|
2008-08-28 13:43:00 +00:00
|
|
|
|
|
|
|
if (remoteheads->next) {
|
2011-02-22 23:41:59 +00:00
|
|
|
error(_("Not handling anything other than two heads merge."));
|
2008-08-28 13:43:00 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2019-01-12 02:13:29 +00:00
|
|
|
init_merge_options(&o, the_repository);
|
2008-08-28 13:43:00 +00:00
|
|
|
if (!strcmp(strategy, "subtree"))
|
2008-07-01 05:18:57 +00:00
|
|
|
o.subtree_shift = "";
|
2009-11-26 02:23:55 +00:00
|
|
|
|
2011-02-20 09:53:21 +00:00
|
|
|
o.show_rename_progress =
|
|
|
|
show_progress == -1 ? isatty(2) : show_progress;
|
2010-08-05 11:32:41 +00:00
|
|
|
|
2010-08-26 05:47:58 +00:00
|
|
|
for (x = 0; x < xopts_nr; x++)
|
|
|
|
if (parse_merge_opt(&o, xopts[x]))
|
2021-08-04 23:50:54 +00:00
|
|
|
die(_("unknown strategy option: -X%s"), xopts[x]);
|
2008-08-28 13:43:00 +00:00
|
|
|
|
|
|
|
o.branch1 = head_arg;
|
2011-11-07 21:26:22 +00:00
|
|
|
o.branch2 = merge_remote_util(remoteheads->item)->name;
|
2008-08-28 13:43:00 +00:00
|
|
|
|
|
|
|
for (j = common; j; j = j->next)
|
|
|
|
commit_list_insert(j->item, &reversed);
|
|
|
|
|
2022-11-19 13:07:38 +00:00
|
|
|
repo_hold_locked_index(the_repository, &lock,
|
|
|
|
LOCK_DIE_ON_ERROR);
|
2020-11-02 23:45:34 +00:00
|
|
|
if (!strcmp(strategy, "ort"))
|
|
|
|
clean = merge_ort_recursive(&o, head, remoteheads->item,
|
|
|
|
reversed, &result);
|
|
|
|
else
|
|
|
|
clean = merge_recursive(&o, head, remoteheads->item,
|
|
|
|
reversed, &result);
|
2022-07-23 01:53:14 +00:00
|
|
|
if (clean < 0) {
|
|
|
|
rollback_lock_file(&lock);
|
|
|
|
return 2;
|
|
|
|
}
|
2018-03-01 20:40:20 +00:00
|
|
|
if (write_locked_index(&the_index, &lock,
|
|
|
|
COMMIT_LOCK | SKIP_IF_UNCHANGED))
|
2018-07-21 07:49:19 +00:00
|
|
|
die(_("unable to write %s"), get_index_file());
|
2008-08-28 13:43:00 +00:00
|
|
|
return clean ? 0 : 1;
|
|
|
|
} else {
|
2018-09-21 15:57:29 +00:00
|
|
|
return try_merge_command(the_repository,
|
|
|
|
strategy, xopts_nr, xopts,
|
|
|
|
common, head_arg, remoteheads);
|
2008-08-28 13:43:00 +00:00
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void count_diff_files(struct diff_queue_struct *q,
|
2022-12-13 11:13:48 +00:00
|
|
|
struct diff_options *opt UNUSED, void *data)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
|
|
|
int *count = data;
|
|
|
|
|
|
|
|
(*count) += q->nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int count_unmerged_entries(void)
|
|
|
|
{
|
|
|
|
int i, ret = 0;
|
|
|
|
|
2022-11-19 13:07:34 +00:00
|
|
|
for (i = 0; i < the_index.cache_nr; i++)
|
|
|
|
if (ce_stage(the_index.cache[i]))
|
2008-07-07 17:24:20 +00:00
|
|
|
ret++;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_strategies(const char *string, unsigned attr)
|
|
|
|
{
|
2016-08-05 21:01:35 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (string) {
|
|
|
|
struct string_list list = STRING_LIST_INIT_DUP;
|
|
|
|
struct string_list_item *item;
|
|
|
|
string_list_split(&list, string, ' ', -1);
|
|
|
|
for_each_string_list_item(item, &list)
|
|
|
|
append_strategy(get_strategy(item->string));
|
|
|
|
string_list_clear(&list, 0);
|
2008-07-07 17:24:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
|
|
|
|
if (all_strategy[i].attr & attr)
|
|
|
|
append_strategy(&all_strategy[i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-10-08 18:39:52 +00:00
|
|
|
static void read_merge_msg(struct strbuf *msg)
|
2011-02-15 01:07:50 +00:00
|
|
|
{
|
2018-05-17 22:51:51 +00:00
|
|
|
const char *filename = git_path_merge_msg(the_repository);
|
2011-10-08 18:39:52 +00:00
|
|
|
strbuf_reset(msg);
|
2011-11-16 08:03:36 +00:00
|
|
|
if (strbuf_read_file(msg, filename, 0) < 0)
|
|
|
|
die_errno(_("Could not read from '%s'"), filename);
|
2011-02-15 01:07:50 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 23:15:13 +00:00
|
|
|
static void write_merge_state(struct commit_list *);
|
|
|
|
static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
|
2011-02-15 01:07:50 +00:00
|
|
|
{
|
2011-10-08 18:39:52 +00:00
|
|
|
if (err_msg)
|
|
|
|
error("%s", err_msg);
|
|
|
|
fprintf(stderr,
|
|
|
|
_("Not committing merge; use 'git commit' to complete the merge.\n"));
|
2012-04-16 23:15:13 +00:00
|
|
|
write_merge_state(remoteheads);
|
2011-10-08 18:39:52 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-01-30 20:25:30 +00:00
|
|
|
static const char merge_editor_comment[] =
|
|
|
|
N_("Please enter a commit message to explain why this merge is necessary,\n"
|
|
|
|
"especially if it merges an updated upstream into a topic branch.\n"
|
2019-04-17 10:23:27 +00:00
|
|
|
"\n");
|
|
|
|
|
|
|
|
static const char scissors_editor_comment[] =
|
|
|
|
N_("An empty message aborts the commit.\n");
|
|
|
|
|
|
|
|
static const char no_scissors_editor_comment[] =
|
|
|
|
N_("Lines starting with '%c' will be ignored, and an empty message aborts\n"
|
2012-01-30 20:25:30 +00:00
|
|
|
"the commit.\n");
|
|
|
|
|
2017-08-23 12:10:45 +00:00
|
|
|
static void write_merge_heads(struct commit_list *);
|
2012-04-16 23:15:13 +00:00
|
|
|
static void prepare_to_commit(struct commit_list *remoteheads)
|
2011-10-08 18:39:52 +00:00
|
|
|
{
|
|
|
|
struct strbuf msg = STRBUF_INIT;
|
2019-08-07 18:57:07 +00:00
|
|
|
const char *index_file = get_index_file();
|
|
|
|
|
2022-03-07 12:33:45 +00:00
|
|
|
if (!no_verify) {
|
hooks: fix an obscure TOCTOU "did we just run a hook?" race
Fix a Time-of-check to time-of-use (TOCTOU) race in code added in
680ee550d72 (commit: skip discarding the index if there is no
pre-commit hook, 2017-08-14).
This obscure race condition can occur if we e.g. ran the "pre-commit"
hook and it modified the index, but hook_exists() returns false later
on (e.g., because the hook itself went away, the directory became
unreadable, etc.). Then we won't call discard_cache() when we should
have.
The race condition itself probably doesn't matter, and users would
have been unlikely to run into it in practice. This problem has been
noted on-list when 680ee550d72 was discussed[1], but had not been
fixed.
This change is mainly intended to improve the readability of the code
involved, and to make reasoning about it more straightforward. It
wasn't as obvious what we were trying to do here, but by having an
"invoked_hook" it's clearer that e.g. our discard_cache() is happening
because of the earlier hook execution.
Let's also change this for the push-to-checkout hook. Now instead of
checking if the hook exists and either doing a push to checkout or a
push to deploy we'll always attempt a push to checkout. If the hook
doesn't exist we'll fall back on push to deploy. The same behavior as
before, without the TOCTOU race. See 0855331941b (receive-pack:
support push-to-checkout hook, 2014-12-01) for the introduction of the
previous behavior.
This leaves uses of hook_exists() in two places that matter. The
"reference-transaction" check in refs.c, see 67541597670 (refs:
implement reference transaction hook, 2020-06-19), and the
"prepare-commit-msg" hook, see 66618a50f9c (sequencer: run
'prepare-commit-msg' hook, 2018-01-24).
In both of those cases we're saving ourselves CPU time by not
preparing data for the hook that we'll then do nothing with if we
don't have the hook. So using this "invoked_hook" pattern doesn't make
sense in those cases.
The "reference-transaction" and "prepare-commit-msg" hook also aren't
racy. In those cases we'll skip the hook runs if we race with a new
hook being added, whereas in the TOCTOU races being fixed here we were
incorrectly skipping the required post-hook logic.
1. https://lore.kernel.org/git/20170810191613.kpmhzg4seyxy3cpq@sigill.intra.peff.net/
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-07 12:33:46 +00:00
|
|
|
int invoked_hook;
|
|
|
|
|
|
|
|
if (run_commit_hook(0 < option_edit, index_file, &invoked_hook,
|
2022-03-07 12:33:45 +00:00
|
|
|
"pre-merge-commit", NULL))
|
|
|
|
abort_commit(remoteheads, NULL);
|
|
|
|
/*
|
|
|
|
* Re-read the index as pre-merge-commit hook could have updated it,
|
|
|
|
* and write it out as a tree. We must do this before we invoke
|
|
|
|
* the editor and after we invoke run_status above.
|
|
|
|
*/
|
hooks: fix an obscure TOCTOU "did we just run a hook?" race
Fix a Time-of-check to time-of-use (TOCTOU) race in code added in
680ee550d72 (commit: skip discarding the index if there is no
pre-commit hook, 2017-08-14).
This obscure race condition can occur if we e.g. ran the "pre-commit"
hook and it modified the index, but hook_exists() returns false later
on (e.g., because the hook itself went away, the directory became
unreadable, etc.). Then we won't call discard_cache() when we should
have.
The race condition itself probably doesn't matter, and users would
have been unlikely to run into it in practice. This problem has been
noted on-list when 680ee550d72 was discussed[1], but had not been
fixed.
This change is mainly intended to improve the readability of the code
involved, and to make reasoning about it more straightforward. It
wasn't as obvious what we were trying to do here, but by having an
"invoked_hook" it's clearer that e.g. our discard_cache() is happening
because of the earlier hook execution.
Let's also change this for the push-to-checkout hook. Now instead of
checking if the hook exists and either doing a push to checkout or a
push to deploy we'll always attempt a push to checkout. If the hook
doesn't exist we'll fall back on push to deploy. The same behavior as
before, without the TOCTOU race. See 0855331941b (receive-pack:
support push-to-checkout hook, 2014-12-01) for the introduction of the
previous behavior.
This leaves uses of hook_exists() in two places that matter. The
"reference-transaction" check in refs.c, see 67541597670 (refs:
implement reference transaction hook, 2020-06-19), and the
"prepare-commit-msg" hook, see 66618a50f9c (sequencer: run
'prepare-commit-msg' hook, 2018-01-24).
In both of those cases we're saving ourselves CPU time by not
preparing data for the hook that we'll then do nothing with if we
don't have the hook. So using this "invoked_hook" pattern doesn't make
sense in those cases.
The "reference-transaction" and "prepare-commit-msg" hook also aren't
racy. In those cases we'll skip the hook runs if we race with a new
hook being added, whereas in the TOCTOU races being fixed here we were
incorrectly skipping the required post-hook logic.
1. https://lore.kernel.org/git/20170810191613.kpmhzg4seyxy3cpq@sigill.intra.peff.net/
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-07 12:33:46 +00:00
|
|
|
if (invoked_hook)
|
2022-11-19 13:07:38 +00:00
|
|
|
discard_index(&the_index);
|
2022-03-07 12:33:45 +00:00
|
|
|
}
|
2022-11-19 13:07:38 +00:00
|
|
|
read_index_from(&the_index, index_file, get_git_dir());
|
2011-10-08 18:39:52 +00:00
|
|
|
strbuf_addbuf(&msg, &merge_msg);
|
2017-08-23 12:10:43 +00:00
|
|
|
if (squash)
|
|
|
|
BUG("the control must not reach here under --squash");
|
2019-04-17 10:23:27 +00:00
|
|
|
if (0 < option_edit) {
|
|
|
|
strbuf_addch(&msg, '\n');
|
|
|
|
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
|
|
|
|
wt_status_append_cut_line(&msg);
|
|
|
|
strbuf_commented_addf(&msg, "\n");
|
|
|
|
}
|
|
|
|
strbuf_commented_addf(&msg, _(merge_editor_comment));
|
2021-08-08 03:38:34 +00:00
|
|
|
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
|
|
|
|
strbuf_commented_addf(&msg, _(scissors_editor_comment));
|
|
|
|
else
|
|
|
|
strbuf_commented_addf(&msg,
|
|
|
|
_(no_scissors_editor_comment), comment_line_char);
|
2019-04-17 10:23:27 +00:00
|
|
|
}
|
2017-07-04 09:33:06 +00:00
|
|
|
if (signoff)
|
|
|
|
append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0);
|
2017-08-23 12:10:45 +00:00
|
|
|
write_merge_heads(remoteheads);
|
2018-05-17 22:51:51 +00:00
|
|
|
write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
|
hooks: fix an obscure TOCTOU "did we just run a hook?" race
Fix a Time-of-check to time-of-use (TOCTOU) race in code added in
680ee550d72 (commit: skip discarding the index if there is no
pre-commit hook, 2017-08-14).
This obscure race condition can occur if we e.g. ran the "pre-commit"
hook and it modified the index, but hook_exists() returns false later
on (e.g., because the hook itself went away, the directory became
unreadable, etc.). Then we won't call discard_cache() when we should
have.
The race condition itself probably doesn't matter, and users would
have been unlikely to run into it in practice. This problem has been
noted on-list when 680ee550d72 was discussed[1], but had not been
fixed.
This change is mainly intended to improve the readability of the code
involved, and to make reasoning about it more straightforward. It
wasn't as obvious what we were trying to do here, but by having an
"invoked_hook" it's clearer that e.g. our discard_cache() is happening
because of the earlier hook execution.
Let's also change this for the push-to-checkout hook. Now instead of
checking if the hook exists and either doing a push to checkout or a
push to deploy we'll always attempt a push to checkout. If the hook
doesn't exist we'll fall back on push to deploy. The same behavior as
before, without the TOCTOU race. See 0855331941b (receive-pack:
support push-to-checkout hook, 2014-12-01) for the introduction of the
previous behavior.
This leaves uses of hook_exists() in two places that matter. The
"reference-transaction" check in refs.c, see 67541597670 (refs:
implement reference transaction hook, 2020-06-19), and the
"prepare-commit-msg" hook, see 66618a50f9c (sequencer: run
'prepare-commit-msg' hook, 2018-01-24).
In both of those cases we're saving ourselves CPU time by not
preparing data for the hook that we'll then do nothing with if we
don't have the hook. So using this "invoked_hook" pattern doesn't make
sense in those cases.
The "reference-transaction" and "prepare-commit-msg" hook also aren't
racy. In those cases we'll skip the hook runs if we race with a new
hook being added, whereas in the TOCTOU races being fixed here we were
incorrectly skipping the required post-hook logic.
1. https://lore.kernel.org/git/20170810191613.kpmhzg4seyxy3cpq@sigill.intra.peff.net/
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-07 12:33:46 +00:00
|
|
|
if (run_commit_hook(0 < option_edit, get_index_file(), NULL,
|
|
|
|
"prepare-commit-msg",
|
2018-05-17 22:51:51 +00:00
|
|
|
git_path_merge_msg(the_repository), "merge", NULL))
|
2013-01-02 18:42:50 +00:00
|
|
|
abort_commit(remoteheads, NULL);
|
2012-01-11 06:44:45 +00:00
|
|
|
if (0 < option_edit) {
|
2018-05-17 22:51:51 +00:00
|
|
|
if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL))
|
2012-04-16 23:15:13 +00:00
|
|
|
abort_commit(remoteheads, NULL);
|
2011-10-08 18:39:52 +00:00
|
|
|
}
|
2017-09-07 22:04:29 +00:00
|
|
|
|
2019-08-07 18:57:06 +00:00
|
|
|
if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(),
|
hooks: fix an obscure TOCTOU "did we just run a hook?" race
Fix a Time-of-check to time-of-use (TOCTOU) race in code added in
680ee550d72 (commit: skip discarding the index if there is no
pre-commit hook, 2017-08-14).
This obscure race condition can occur if we e.g. ran the "pre-commit"
hook and it modified the index, but hook_exists() returns false later
on (e.g., because the hook itself went away, the directory became
unreadable, etc.). Then we won't call discard_cache() when we should
have.
The race condition itself probably doesn't matter, and users would
have been unlikely to run into it in practice. This problem has been
noted on-list when 680ee550d72 was discussed[1], but had not been
fixed.
This change is mainly intended to improve the readability of the code
involved, and to make reasoning about it more straightforward. It
wasn't as obvious what we were trying to do here, but by having an
"invoked_hook" it's clearer that e.g. our discard_cache() is happening
because of the earlier hook execution.
Let's also change this for the push-to-checkout hook. Now instead of
checking if the hook exists and either doing a push to checkout or a
push to deploy we'll always attempt a push to checkout. If the hook
doesn't exist we'll fall back on push to deploy. The same behavior as
before, without the TOCTOU race. See 0855331941b (receive-pack:
support push-to-checkout hook, 2014-12-01) for the introduction of the
previous behavior.
This leaves uses of hook_exists() in two places that matter. The
"reference-transaction" check in refs.c, see 67541597670 (refs:
implement reference transaction hook, 2020-06-19), and the
"prepare-commit-msg" hook, see 66618a50f9c (sequencer: run
'prepare-commit-msg' hook, 2018-01-24).
In both of those cases we're saving ourselves CPU time by not
preparing data for the hook that we'll then do nothing with if we
don't have the hook. So using this "invoked_hook" pattern doesn't make
sense in those cases.
The "reference-transaction" and "prepare-commit-msg" hook also aren't
racy. In those cases we'll skip the hook runs if we race with a new
hook being added, whereas in the TOCTOU races being fixed here we were
incorrectly skipping the required post-hook logic.
1. https://lore.kernel.org/git/20170810191613.kpmhzg4seyxy3cpq@sigill.intra.peff.net/
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-03-07 12:33:46 +00:00
|
|
|
NULL, "commit-msg",
|
2018-05-17 22:51:51 +00:00
|
|
|
git_path_merge_msg(the_repository), NULL))
|
2017-09-07 22:04:29 +00:00
|
|
|
abort_commit(remoteheads, NULL);
|
|
|
|
|
2011-10-08 18:39:52 +00:00
|
|
|
read_merge_msg(&msg);
|
2019-04-17 10:23:27 +00:00
|
|
|
cleanup_message(&msg, cleanup_mode, 0);
|
2011-10-08 18:39:52 +00:00
|
|
|
if (!msg.len)
|
2012-04-16 23:15:13 +00:00
|
|
|
abort_commit(remoteheads, _("Empty commit message."));
|
2011-10-08 18:39:52 +00:00
|
|
|
strbuf_release(&merge_msg);
|
|
|
|
strbuf_addbuf(&merge_msg, &msg);
|
|
|
|
strbuf_release(&msg);
|
2011-02-15 01:07:50 +00:00
|
|
|
}
|
|
|
|
|
2012-04-16 23:15:13 +00:00
|
|
|
static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id result_tree, result_commit;
|
2014-07-10 09:41:40 +00:00
|
|
|
struct commit_list *parents, **pptr = &parents;
|
2016-04-10 06:13:40 +00:00
|
|
|
|
2022-11-19 13:07:38 +00:00
|
|
|
if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
|
|
|
|
SKIP_IF_UNCHANGED, 0, NULL, NULL,
|
|
|
|
NULL) < 0)
|
2016-04-10 06:13:40 +00:00
|
|
|
return error(_("Unable to write index."));
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
write_tree_trivial(&result_tree);
|
2011-02-22 23:42:02 +00:00
|
|
|
printf(_("Wonderful.\n"));
|
2014-07-10 09:41:40 +00:00
|
|
|
pptr = commit_list_append(head, pptr);
|
|
|
|
pptr = commit_list_append(remoteheads->item, pptr);
|
2012-04-16 23:15:13 +00:00
|
|
|
prepare_to_commit(remoteheads);
|
2018-01-28 00:13:16 +00:00
|
|
|
if (commit_tree(merge_msg.buf, merge_msg.len, &result_tree, parents,
|
|
|
|
&result_commit, NULL, sign_commit))
|
2011-12-15 13:47:21 +00:00
|
|
|
die(_("failed to write commit object"));
|
2017-02-21 23:47:28 +00:00
|
|
|
finish(head, remoteheads, &result_commit, "In-index merge");
|
2019-05-09 10:10:27 +00:00
|
|
|
remove_merge_branch_state(the_repository);
|
2008-07-07 17:24:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-17 11:57:44 +00:00
|
|
|
static int finish_automerge(struct commit *head,
|
2012-04-17 19:22:26 +00:00
|
|
|
int head_subsumed,
|
2011-09-17 11:57:44 +00:00
|
|
|
struct commit_list *common,
|
2012-04-16 23:15:13 +00:00
|
|
|
struct commit_list *remoteheads,
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id *result_tree,
|
2008-07-07 17:24:20 +00:00
|
|
|
const char *wt_strategy)
|
|
|
|
{
|
2012-04-17 19:22:26 +00:00
|
|
|
struct commit_list *parents = NULL;
|
2008-07-07 17:24:20 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id result_commit;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2019-07-09 03:15:59 +00:00
|
|
|
write_tree_trivial(result_tree);
|
2008-07-07 17:24:20 +00:00
|
|
|
free_commit_list(common);
|
2012-04-17 19:22:26 +00:00
|
|
|
parents = remoteheads;
|
2013-07-02 14:47:57 +00:00
|
|
|
if (!head_subsumed || fast_forward == FF_NO)
|
2011-09-17 11:57:44 +00:00
|
|
|
commit_list_insert(head, &parents);
|
2012-04-16 23:15:13 +00:00
|
|
|
prepare_to_commit(remoteheads);
|
2018-01-28 00:13:16 +00:00
|
|
|
if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
|
|
|
|
&result_commit, NULL, sign_commit))
|
2011-12-15 13:47:21 +00:00
|
|
|
die(_("failed to write commit object"));
|
2011-05-25 19:43:59 +00:00
|
|
|
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
2017-02-21 23:47:28 +00:00
|
|
|
finish(head, remoteheads, &result_commit, buf.buf);
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_release(&buf);
|
2019-05-09 10:10:27 +00:00
|
|
|
remove_merge_branch_state(the_repository);
|
2008-07-07 17:24:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-24 18:27:22 +00:00
|
|
|
static int suggest_conflicts(void)
|
2008-07-07 17:24:20 +00:00
|
|
|
{
|
2011-11-16 08:03:36 +00:00
|
|
|
const char *filename;
|
2008-07-07 17:24:20 +00:00
|
|
|
FILE *fp;
|
2014-10-24 18:34:59 +00:00
|
|
|
struct strbuf msgbuf = STRBUF_INIT;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2018-05-17 22:51:51 +00:00
|
|
|
filename = git_path_merge_msg(the_repository);
|
2017-05-03 10:16:46 +00:00
|
|
|
fp = xfopen(filename, "a");
|
2014-10-24 18:34:59 +00:00
|
|
|
|
2019-04-17 10:23:28 +00:00
|
|
|
/*
|
|
|
|
* We can't use cleanup_mode because if we're not using the editor,
|
|
|
|
* get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
|
|
|
|
* though the message is meant to be processed later by git-commit.
|
|
|
|
* Thus, we will get the cleanup mode which is returned when we _are_
|
|
|
|
* using an editor.
|
|
|
|
*/
|
2019-04-17 10:23:30 +00:00
|
|
|
append_conflicts_hint(&the_index, &msgbuf,
|
|
|
|
get_cleanup_mode(cleanup_arg, 1));
|
2014-10-24 18:34:59 +00:00
|
|
|
fputs(msgbuf.buf, fp);
|
2014-12-24 00:18:38 +00:00
|
|
|
strbuf_release(&msgbuf);
|
2008-07-07 17:24:20 +00:00
|
|
|
fclose(fp);
|
2018-09-21 15:57:32 +00:00
|
|
|
repo_rerere(the_repository, allow_rerere_auto);
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Automatic merge failed; "
|
|
|
|
"fix conflicts and then commit the result.\n"));
|
2008-07-07 17:24:20 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int evaluate_result(void)
|
|
|
|
{
|
|
|
|
int cnt = 0;
|
|
|
|
struct rev_info rev;
|
|
|
|
|
|
|
|
/* Check how many files differ. */
|
2018-09-21 15:57:38 +00:00
|
|
|
repo_init_revisions(the_repository, &rev, "");
|
2008-07-07 17:24:20 +00:00
|
|
|
setup_revisions(0, NULL, &rev, NULL);
|
|
|
|
rev.diffopt.output_format |=
|
|
|
|
DIFF_FORMAT_CALLBACK;
|
|
|
|
rev.diffopt.format_callback = count_diff_files;
|
|
|
|
rev.diffopt.format_callback_data = &cnt;
|
|
|
|
run_diff_files(&rev, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check how many unmerged entries are
|
|
|
|
* there.
|
|
|
|
*/
|
|
|
|
cnt += count_unmerged_entries();
|
|
|
|
|
2022-04-13 20:01:36 +00:00
|
|
|
release_revisions(&rev);
|
2008-07-07 17:24:20 +00:00
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2011-03-24 06:48:24 +00:00
|
|
|
/*
|
2013-07-03 09:12:34 +00:00
|
|
|
* Pretend as if the user told us to merge with the remote-tracking
|
2011-03-24 06:48:24 +00:00
|
|
|
* branch we have for the upstream of the current branch
|
|
|
|
*/
|
|
|
|
static int setup_with_upstream(const char ***argv)
|
|
|
|
{
|
|
|
|
struct branch *branch = branch_get(NULL);
|
|
|
|
int i;
|
|
|
|
const char **args;
|
|
|
|
|
|
|
|
if (!branch)
|
2011-04-10 19:34:04 +00:00
|
|
|
die(_("No current branch."));
|
remote.c: drop "remote" pointer from "struct branch"
When we create each branch struct, we fill in the
"remote_name" field from the config, and then fill in the
actual "remote" field (with a "struct remote") based on that
name. However, it turns out that nobody really cares about
the latter field. The only two sites that access it at all
are:
1. git-merge, which uses it to notice when the branch does
not have a remote defined. But we can easily replace this
with looking at remote_name instead.
2. remote.c itself, when setting up the @{upstream} merge
config. But we don't need to save the "remote" in the
"struct branch" for that; we can just look it up for
the duration of the operation.
So there is no need to have both fields; they are redundant
with each other (the struct remote contains the name, or you
can look up the struct from the name). It would be nice to
simplify this, especially as we are going to add matching
pushremote config in a future patch (and it would be nice to
keep them consistent).
So which one do we keep and which one do we get rid of?
If we had a lot of callers accessing the struct, it would be
more efficient to keep it (since you have to do a lookup to
go from the name to the struct, but not vice versa). But we
don't have a lot of callers; we have exactly one, so
efficiency doesn't matter. We can decide this based on
simplicity and readability.
And the meaning of the struct value is somewhat unclear. Is
it always the remote matching remote_name? If remote_name is
NULL (i.e., no per-branch config), does the struct fall back
to the "origin" remote, or is it also NULL? These questions
will get even more tricky with pushremotes, whose fallback
behavior is more complicated. So let's just store the name,
which pretty clearly represents the branch.*.remote config.
Any lookup or fallback behavior can then be implemented in
helper functions.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-21 04:45:13 +00:00
|
|
|
if (!branch->remote_name)
|
2011-04-10 19:34:04 +00:00
|
|
|
die(_("No remote for the current branch."));
|
2011-03-24 06:48:24 +00:00
|
|
|
if (!branch->merge_nr)
|
2011-04-10 19:34:04 +00:00
|
|
|
die(_("No default upstream defined for the current branch."));
|
2011-03-24 06:48:24 +00:00
|
|
|
|
2016-02-22 22:44:35 +00:00
|
|
|
args = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));
|
2011-03-24 06:48:24 +00:00
|
|
|
for (i = 0; i < branch->merge_nr; i++) {
|
|
|
|
if (!branch->merge[i]->dst)
|
2013-07-03 09:12:34 +00:00
|
|
|
die(_("No remote-tracking branch for %s from %s"),
|
2011-03-24 06:48:24 +00:00
|
|
|
branch->merge[i]->src, branch->remote_name);
|
|
|
|
args[i] = branch->merge[i]->dst;
|
|
|
|
}
|
|
|
|
args[i] = NULL;
|
|
|
|
*argv = args;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2017-08-23 12:10:44 +00:00
|
|
|
static void write_merge_heads(struct commit_list *remoteheads)
|
2011-10-08 18:39:52 +00:00
|
|
|
{
|
|
|
|
struct commit_list *j;
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
2011-11-07 22:45:10 +00:00
|
|
|
for (j = remoteheads; j; j = j->next) {
|
2015-11-10 02:22:28 +00:00
|
|
|
struct object_id *oid;
|
2011-11-07 22:45:10 +00:00
|
|
|
struct commit *c = j->item;
|
2018-05-19 05:28:30 +00:00
|
|
|
struct merge_remote_desc *desc;
|
|
|
|
|
|
|
|
desc = merge_remote_util(c);
|
|
|
|
if (desc && desc->obj) {
|
|
|
|
oid = &desc->obj->oid;
|
2011-11-07 22:45:10 +00:00
|
|
|
} else {
|
2015-11-10 02:22:28 +00:00
|
|
|
oid = &c->object.oid;
|
2011-11-07 22:45:10 +00:00
|
|
|
}
|
2015-11-10 02:22:28 +00:00
|
|
|
strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
|
2011-11-07 22:45:10 +00:00
|
|
|
}
|
2018-05-17 22:51:51 +00:00
|
|
|
write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len);
|
2011-11-16 08:03:36 +00:00
|
|
|
|
2011-10-08 18:39:52 +00:00
|
|
|
strbuf_reset(&buf);
|
2013-07-02 14:47:57 +00:00
|
|
|
if (fast_forward == FF_NO)
|
2016-09-15 18:31:00 +00:00
|
|
|
strbuf_addstr(&buf, "no-ff");
|
2018-05-17 22:51:51 +00:00
|
|
|
write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len);
|
2017-08-30 17:49:50 +00:00
|
|
|
strbuf_release(&buf);
|
2011-10-08 18:39:52 +00:00
|
|
|
}
|
|
|
|
|
2017-08-23 12:10:44 +00:00
|
|
|
static void write_merge_state(struct commit_list *remoteheads)
|
|
|
|
{
|
|
|
|
write_merge_heads(remoteheads);
|
|
|
|
strbuf_addch(&merge_msg, '\n');
|
2018-05-17 22:51:51 +00:00
|
|
|
write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf,
|
|
|
|
merge_msg.len);
|
2017-08-23 12:10:44 +00:00
|
|
|
}
|
|
|
|
|
2012-01-11 06:44:45 +00:00
|
|
|
static int default_edit_option(void)
|
|
|
|
{
|
|
|
|
static const char name[] = "GIT_MERGE_AUTOEDIT";
|
|
|
|
const char *e = getenv(name);
|
|
|
|
struct stat st_stdin, st_stdout;
|
|
|
|
|
|
|
|
if (have_message)
|
|
|
|
/* an explicit -m msg without --[no-]edit */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (e) {
|
2017-08-07 18:20:49 +00:00
|
|
|
int v = git_parse_maybe_bool(e);
|
2012-01-11 06:44:45 +00:00
|
|
|
if (v < 0)
|
2016-06-17 20:21:17 +00:00
|
|
|
die(_("Bad value '%s' in environment '%s'"), e, name);
|
2012-01-11 06:44:45 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use editor if stdin and stdout are the same and is a tty */
|
|
|
|
return (!fstat(0, &st_stdin) &&
|
|
|
|
!fstat(1, &st_stdout) &&
|
2012-02-23 19:24:44 +00:00
|
|
|
isatty(0) && isatty(1) &&
|
2012-01-11 06:44:45 +00:00
|
|
|
st_stdin.st_dev == st_stdout.st_dev &&
|
|
|
|
st_stdin.st_ino == st_stdout.st_ino &&
|
|
|
|
st_stdin.st_mode == st_stdout.st_mode);
|
|
|
|
}
|
|
|
|
|
2015-04-25 19:00:14 +00:00
|
|
|
static struct commit_list *reduce_parents(struct commit *head_commit,
|
|
|
|
int *head_subsumed,
|
|
|
|
struct commit_list *remoteheads)
|
2012-04-17 18:31:10 +00:00
|
|
|
{
|
2015-10-24 16:21:31 +00:00
|
|
|
struct commit_list *parents, **remotes;
|
2012-04-17 18:31:10 +00:00
|
|
|
|
2015-04-25 17:25:43 +00:00
|
|
|
/*
|
|
|
|
* Is the current HEAD reachable from another commit being
|
|
|
|
* merged? If so we do not want to record it as a parent of
|
|
|
|
* the resulting merge, unless --no-ff is given. We will flip
|
|
|
|
* this variable to 0 when we find HEAD among the independent
|
|
|
|
* tips being merged.
|
|
|
|
*/
|
|
|
|
*head_subsumed = 1;
|
2012-04-17 19:22:26 +00:00
|
|
|
|
2015-04-25 17:25:43 +00:00
|
|
|
/* Find what parents to record by checking independent ones. */
|
2012-04-17 19:22:26 +00:00
|
|
|
parents = reduce_heads(remoteheads);
|
2017-11-07 20:39:45 +00:00
|
|
|
free_commit_list(remoteheads);
|
2012-04-17 19:22:26 +00:00
|
|
|
|
2015-10-24 16:21:31 +00:00
|
|
|
remoteheads = NULL;
|
|
|
|
remotes = &remoteheads;
|
|
|
|
while (parents) {
|
|
|
|
struct commit *commit = pop_commit(&parents);
|
2012-04-17 19:22:26 +00:00
|
|
|
if (commit == head_commit)
|
|
|
|
*head_subsumed = 0;
|
|
|
|
else
|
|
|
|
remotes = &commit_list_insert(commit, remotes)->next;
|
|
|
|
}
|
2012-04-17 18:31:10 +00:00
|
|
|
return remoteheads;
|
|
|
|
}
|
2012-01-11 06:44:45 +00:00
|
|
|
|
2015-04-26 01:29:44 +00:00
|
|
|
static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *merge_msg)
|
|
|
|
{
|
|
|
|
struct fmt_merge_msg_opts opts;
|
|
|
|
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
|
|
|
opts.add_title = !have_message;
|
|
|
|
opts.shortlog_len = shortlog_len;
|
|
|
|
opts.credit_people = (0 < option_edit);
|
merge: allow to pretend a merge is made into a different branch
When a series of patches for a topic-B depends on having topic-A,
the workflow to prepare the topic-B branch would look like this:
$ git checkout -b topic-B main
$ git merge --no-ff --no-edit topic-A
$ git am <mbox-for-topic-B
When topic-A gets updated, recreating the first merge and rebasing
the rest of the topic-B, all on detached HEAD, is a useful
technique. After updating topic-A with its new round of patches:
$ git checkout topic-B
$ prev=$(git rev-parse 'HEAD^{/^Merge branch .topic-A. into}')
$ git checkout --detach $prev^1
$ git merge --no-ff --no-edit topic-A
$ git rebase --onto HEAD $prev @{-1}^0
$ git checkout -B @{-1}
This will
(0) check out the current topic-B.
(1) find the previous merge of topic-A into topic-B.
(2) detach the HEAD to the parent of the previous merge.
(3) merge the updated topic-A to it.
(4) reapply the patches to rebuild the rest of topic-B.
(5) update topic-B with the result.
without contaminating the reflog of topic-B too much. topic-B@{1}
is the "logically previous" state before topic-A got updated, for
example. At (4), comparison (e.g. range-diff) between HEAD and
@{-1} is a meaningful way to sanity check the result, and the same
can be done at (5) by comparing topic-B and topic-B@{1}.
But there is one glitch. The merge into the detached HEAD done in
the step (3) above gives us "Merge branch 'topic-A' into HEAD", and
does not say "into topic-B".
Teach the "--into-name=<branch>" option to "git merge" and its
underlying "git fmt-merge-message", to pretend as if we were merging
into <branch>, no matter what branch we are actually merging into,
when they prepare the merge message. The pretend name honors the
usual "into <target>" suppression mechanism, which can be seen in
the tests added here.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-20 22:53:43 +00:00
|
|
|
opts.into_name = into_name;
|
2015-04-26 01:29:44 +00:00
|
|
|
|
|
|
|
fmt_merge_msg(merge_names, merge_msg, &opts);
|
|
|
|
if (merge_msg->len)
|
|
|
|
strbuf_setlen(merge_msg, merge_msg->len - 1);
|
|
|
|
}
|
|
|
|
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)
|
|
|
|
{
|
|
|
|
const char *filename;
|
|
|
|
int fd, pos, npos;
|
|
|
|
struct strbuf fetch_head_file = STRBUF_INIT;
|
2018-07-16 01:28:03 +00:00
|
|
|
const unsigned hexsz = the_hash_algo->hexsz;
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
|
|
|
|
if (!merge_names)
|
|
|
|
merge_names = &fetch_head_file;
|
|
|
|
|
2018-05-17 22:51:51 +00:00
|
|
|
filename = git_path_fetch_head(the_repository);
|
2021-08-25 20:16:46 +00:00
|
|
|
fd = xopen(filename, O_RDONLY);
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
|
|
|
|
if (strbuf_read(merge_names, fd, 0) < 0)
|
|
|
|
die_errno(_("could not read '%s'"), filename);
|
|
|
|
if (close(fd) < 0)
|
|
|
|
die_errno(_("could not close '%s'"), filename);
|
|
|
|
|
|
|
|
for (pos = 0; pos < merge_names->len; pos = npos) {
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id oid;
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
char *ptr;
|
|
|
|
struct commit *commit;
|
|
|
|
|
|
|
|
ptr = strchr(merge_names->buf + pos, '\n');
|
|
|
|
if (ptr)
|
|
|
|
npos = ptr - merge_names->buf + 1;
|
|
|
|
else
|
|
|
|
npos = merge_names->len;
|
|
|
|
|
2018-07-16 01:28:03 +00:00
|
|
|
if (npos - pos < hexsz + 2 ||
|
2017-02-21 23:47:28 +00:00
|
|
|
get_oid_hex(merge_names->buf + pos, &oid))
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
commit = NULL; /* bad */
|
2018-07-16 01:28:03 +00:00
|
|
|
else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
continue; /* not-for-merge */
|
|
|
|
else {
|
2018-07-16 01:28:03 +00:00
|
|
|
char saved = merge_names->buf[pos + hexsz];
|
|
|
|
merge_names->buf[pos + hexsz] = '\0';
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
commit = get_merge_parent(merge_names->buf + pos);
|
2018-07-16 01:28:03 +00:00
|
|
|
merge_names->buf[pos + hexsz] = saved;
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
}
|
|
|
|
if (!commit) {
|
|
|
|
if (ptr)
|
|
|
|
*ptr = '\0';
|
2016-06-17 20:21:17 +00:00
|
|
|
die(_("not something we can merge in %s: %s"),
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
filename, merge_names->buf + pos);
|
|
|
|
}
|
|
|
|
remotes = &commit_list_insert(commit, remotes)->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (merge_names == &fetch_head_file)
|
|
|
|
strbuf_release(&fetch_head_file);
|
|
|
|
}
|
|
|
|
|
2015-04-25 19:00:14 +00:00
|
|
|
static struct commit_list *collect_parents(struct commit *head_commit,
|
|
|
|
int *head_subsumed,
|
2015-04-26 01:34:22 +00:00
|
|
|
int argc, const char **argv,
|
|
|
|
struct strbuf *merge_msg)
|
2015-04-25 19:00:14 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct commit_list *remoteheads = NULL;
|
|
|
|
struct commit_list **remotes = &remoteheads;
|
2015-04-26 01:39:43 +00:00
|
|
|
struct strbuf merge_names = STRBUF_INIT, *autogen = NULL;
|
|
|
|
|
|
|
|
if (merge_msg && (!have_message || shortlog_len))
|
|
|
|
autogen = &merge_names;
|
2015-04-25 19:00:14 +00:00
|
|
|
|
|
|
|
if (head_commit)
|
|
|
|
remotes = &commit_list_insert(head_commit, remotes)->next;
|
|
|
|
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
if (argc == 1 && !strcmp(argv[0], "FETCH_HEAD")) {
|
|
|
|
handle_fetch_head(remotes, autogen);
|
|
|
|
remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
struct commit *commit = get_merge_parent(argv[i]);
|
|
|
|
if (!commit)
|
|
|
|
help_unknown_ref(argv[i], "merge",
|
2016-06-17 20:21:17 +00:00
|
|
|
_("not something we can merge"));
|
merge: handle FETCH_HEAD internally
The collect_parents() function now is responsible for
1. parsing the commits given on the command line into a list of
commits to be merged;
2. filtering these parents into independent ones; and
3. optionally calling fmt_merge_msg() via prepare_merge_message()
to prepare an auto-generated merge log message, using fake
contents that FETCH_HEAD would have had if these commits were
fetched from the current repository with "git pull . $args..."
Make "git merge FETCH_HEAD" to be the same as the traditional
git merge "$(git fmt-merge-msg <.git/FETCH_HEAD)" $commits
invocation of the command in "git pull", where $commits are the ones
that appear in FETCH_HEAD that are not marked as not-for-merge, by
making it do a bit more, specifically:
- noticing "FETCH_HEAD" is the only "commit" on the command line
and picking the commits that are not marked as not-for-merge as
the list of commits to be merged (substitute for step #1 above);
- letting the resulting list fed to step #2 above;
- doing the step #3 above, using the contents of the FETCH_HEAD
instead of fake contents crafted from the list of commits parsed
in the step #1 above.
Note that this changes the semantics. "git merge FETCH_HEAD" has
always behaved as if the first commit in the FETCH_HEAD file were
directly specified on the command line, creating a two-way merge
whose auto-generated merge log said "merge commit xyz". With this
change, if the previous fetch was to grab multiple branches (e.g.
"git fetch $there topic-a topic-b"), the new world order is to
create an octopus, behaving as if "git pull $there topic-a topic-b"
were run. This is a deliberate change to make that happen, and
can be seen in the changes to t3033 tests.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-26 01:47:21 +00:00
|
|
|
remotes = &commit_list_insert(commit, remotes)->next;
|
|
|
|
}
|
|
|
|
remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
|
|
|
|
if (autogen) {
|
|
|
|
struct commit_list *p;
|
|
|
|
for (p = remoteheads; p; p = p->next)
|
|
|
|
merge_name(merge_remote_util(p->item)->name, autogen);
|
|
|
|
}
|
|
|
|
}
|
2015-04-26 01:34:22 +00:00
|
|
|
|
2015-04-26 01:39:43 +00:00
|
|
|
if (autogen) {
|
|
|
|
prepare_merge_message(autogen, merge_msg);
|
|
|
|
strbuf_release(autogen);
|
2015-04-26 01:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return remoteheads;
|
2015-04-25 19:00:14 +00:00
|
|
|
}
|
|
|
|
|
2018-02-14 18:18:55 +00:00
|
|
|
static int merging_a_throwaway_tag(struct commit *commit)
|
|
|
|
{
|
|
|
|
char *tag_ref;
|
|
|
|
struct object_id oid;
|
|
|
|
int is_throwaway_tag = 0;
|
|
|
|
|
|
|
|
/* Are we merging a tag? */
|
|
|
|
if (!merge_remote_util(commit) ||
|
|
|
|
!merge_remote_util(commit)->obj ||
|
|
|
|
merge_remote_util(commit)->obj->type != OBJ_TAG)
|
|
|
|
return is_throwaway_tag;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we know we are merging a tag object. Are we downstream
|
|
|
|
* and following the tags from upstream? If so, we must have
|
|
|
|
* the tag object pointed at by "refs/tags/$T" where $T is the
|
|
|
|
* tagname recorded in the tag object. We want to allow such
|
|
|
|
* a "just to catch up" merge to fast-forward.
|
|
|
|
*
|
|
|
|
* Otherwise, we are playing an integrator's role, making a
|
|
|
|
* merge with a throw-away tag from a contributor with
|
|
|
|
* something like "git pull $contributor $signed_tag".
|
|
|
|
* We want to forbid such a merge from fast-forwarding
|
|
|
|
* by default; otherwise we would not keep the signature
|
|
|
|
* anywhere.
|
|
|
|
*/
|
|
|
|
tag_ref = xstrfmt("refs/tags/%s",
|
|
|
|
((struct tag *)merge_remote_util(commit)->obj)->tag);
|
|
|
|
if (!read_ref(tag_ref, &oid) &&
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-28 21:22:40 +00:00
|
|
|
oideq(&oid, &merge_remote_util(commit)->obj->oid))
|
2018-02-14 18:18:55 +00:00
|
|
|
is_throwaway_tag = 0;
|
|
|
|
else
|
|
|
|
is_throwaway_tag = 1;
|
|
|
|
free(tag_ref);
|
|
|
|
return is_throwaway_tag;
|
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
int cmd_merge(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id result_tree, stash, head_oid;
|
2011-09-17 11:57:44 +00:00
|
|
|
struct commit *head_commit;
|
2008-10-09 19:12:12 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2016-04-07 19:03:06 +00:00
|
|
|
int i, ret = 0, head_subsumed;
|
2008-07-07 17:24:20 +00:00
|
|
|
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
|
|
|
|
struct commit_list *common = NULL;
|
|
|
|
const char *best_strategy = NULL, *wt_strategy = NULL;
|
2022-01-20 07:47:15 +00:00
|
|
|
struct commit_list *remoteheads = NULL, *p;
|
2011-12-13 14:17:48 +00:00
|
|
|
void *branch_to_free;
|
2016-12-14 08:37:55 +00:00
|
|
|
int orig_argc = argc;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2010-10-22 06:49:45 +00:00
|
|
|
if (argc == 2 && !strcmp(argv[1], "-h"))
|
|
|
|
usage_with_options(builtin_merge_usage, builtin_merge_options);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2021-09-08 11:23:57 +00:00
|
|
|
prepare_repo_settings(the_repository);
|
|
|
|
the_repository->settings.command_requires_full_index = 0;
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
/*
|
|
|
|
* Check if we are _not_ on a detached HEAD, i.e. if there is a
|
|
|
|
* current branch.
|
|
|
|
*/
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-15 22:06:55 +00:00
|
|
|
branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
|
2017-08-10 16:47:55 +00:00
|
|
|
if (branch)
|
|
|
|
skip_prefix(branch, "refs/heads/", &branch);
|
2018-05-01 12:47:23 +00:00
|
|
|
|
2020-11-02 23:45:34 +00:00
|
|
|
if (!pull_twohead) {
|
|
|
|
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
|
|
|
|
if (default_strategy && !strcmp(default_strategy, "ort"))
|
|
|
|
pull_twohead = "ort";
|
|
|
|
}
|
|
|
|
|
2018-05-01 12:47:23 +00:00
|
|
|
init_diff_ui_defaults();
|
|
|
|
git_config(git_merge_config, NULL);
|
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
if (!branch || is_null_oid(&head_oid))
|
2011-09-17 11:57:44 +00:00
|
|
|
head_commit = NULL;
|
2011-09-17 11:57:45 +00:00
|
|
|
else
|
Convert lookup_commit* to struct object_id
Convert lookup_commit, lookup_commit_or_die,
lookup_commit_reference, and lookup_commit_reference_gently to take
struct object_id arguments.
Introduce a temporary in parse_object buffer in order to convert this
function. This is required since in order to convert parse_object and
parse_object_buffer, lookup_commit_reference_gently and
lookup_commit_or_die would need to be converted. Not introducing a
temporary would therefore require that lookup_commit_or_die take a
struct object_id *, but lookup_commit would take unsigned char *,
leaving a confusing and hard-to-use interface.
parse_object_buffer will lose this temporary in a later patch.
This commit was created with manual changes to commit.c, commit.h, and
object.c, plus the following semantic patch:
@@
expression E1, E2;
@@
- lookup_commit_reference_gently(E1.hash, E2)
+ lookup_commit_reference_gently(&E1, E2)
@@
expression E1, E2;
@@
- lookup_commit_reference_gently(E1->hash, E2)
+ lookup_commit_reference_gently(E1, E2)
@@
expression E1;
@@
- lookup_commit_reference(E1.hash)
+ lookup_commit_reference(&E1)
@@
expression E1;
@@
- lookup_commit_reference(E1->hash)
+ lookup_commit_reference(E1)
@@
expression E1;
@@
- lookup_commit(E1.hash)
+ lookup_commit(&E1)
@@
expression E1;
@@
- lookup_commit(E1->hash)
+ lookup_commit(E1)
@@
expression E1, E2;
@@
- lookup_commit_or_die(E1.hash, E2)
+ lookup_commit_or_die(&E1, E2)
@@
expression E1, E2;
@@
- lookup_commit_or_die(E1->hash, E2)
+ lookup_commit_or_die(E1, E2)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-06 22:10:10 +00:00
|
|
|
head_commit = lookup_commit_or_die(&head_oid, "HEAD");
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2011-05-05 00:42:51 +00:00
|
|
|
if (branch_mergeoptions)
|
|
|
|
parse_branch_merge_options(branch_mergeoptions);
|
2009-05-23 18:53:12 +00:00
|
|
|
argc = parse_options(argc, argv, prefix, builtin_merge_options,
|
2008-07-07 17:24:20 +00:00
|
|
|
builtin_merge_usage, 0);
|
2011-10-07 06:12:09 +00:00
|
|
|
if (shortlog_len < 0)
|
|
|
|
shortlog_len = (merge_log_config > 0) ? merge_log_config : 0;
|
2010-11-09 21:49:58 +00:00
|
|
|
|
2011-02-20 09:53:21 +00:00
|
|
|
if (verbosity < 0 && show_progress == -1)
|
|
|
|
show_progress = 0;
|
|
|
|
|
2010-11-09 21:49:59 +00:00
|
|
|
if (abort_current_merge) {
|
|
|
|
int nargc = 2;
|
|
|
|
const char *nargv[] = {"reset", "--merge", NULL};
|
2020-04-07 14:28:07 +00:00
|
|
|
struct strbuf stash_oid = STRBUF_INIT;
|
2010-11-09 21:49:59 +00:00
|
|
|
|
2016-12-14 08:37:57 +00:00
|
|
|
if (orig_argc != 2)
|
2016-12-15 17:43:46 +00:00
|
|
|
usage_msg_opt(_("--abort expects no arguments"),
|
2016-12-14 08:37:57 +00:00
|
|
|
builtin_merge_usage, builtin_merge_options);
|
|
|
|
|
2018-05-17 22:51:51 +00:00
|
|
|
if (!file_exists(git_path_merge_head(the_repository)))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("There is no merge to abort (MERGE_HEAD missing)."));
|
2010-11-09 21:49:59 +00:00
|
|
|
|
2020-04-07 14:28:07 +00:00
|
|
|
if (read_oneliner(&stash_oid, git_path_merge_autostash(the_repository),
|
|
|
|
READ_ONELINER_SKIP_IF_EMPTY))
|
|
|
|
unlink(git_path_merge_autostash(the_repository));
|
|
|
|
|
2010-11-09 21:49:59 +00:00
|
|
|
/* Invoke 'git reset --merge' */
|
2011-11-13 10:22:15 +00:00
|
|
|
ret = cmd_reset(nargc, nargv, prefix);
|
2020-04-07 14:28:07 +00:00
|
|
|
|
|
|
|
if (stash_oid.len)
|
|
|
|
apply_autostash_oid(stash_oid.buf);
|
|
|
|
|
|
|
|
strbuf_release(&stash_oid);
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
2010-11-09 21:49:59 +00:00
|
|
|
}
|
|
|
|
|
merge: add --quit
This allows to cancel the current merge without resetting worktree/index,
which is what --abort is for. Like other --quit(s), this is often used
when you forgot that you're in the middle of a merge and already
switched away, doing different things. By the time you've realized, you
can't even continue the merge anymore.
This also makes all in-progress commands, am, merge, rebase, revert and
cherry-pick, take all three --abort, --continue and --quit (bisect has a
different UI).
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-05-18 11:30:43 +00:00
|
|
|
if (quit_current_merge) {
|
|
|
|
if (orig_argc != 2)
|
|
|
|
usage_msg_opt(_("--quit expects no arguments"),
|
|
|
|
builtin_merge_usage,
|
|
|
|
builtin_merge_options);
|
|
|
|
|
|
|
|
remove_merge_branch_state(the_repository);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2016-12-14 08:37:55 +00:00
|
|
|
if (continue_current_merge) {
|
|
|
|
int nargc = 1;
|
|
|
|
const char *nargv[] = {"commit", NULL};
|
|
|
|
|
|
|
|
if (orig_argc != 2)
|
2016-12-15 17:43:46 +00:00
|
|
|
usage_msg_opt(_("--continue expects no arguments"),
|
2016-12-14 08:37:55 +00:00
|
|
|
builtin_merge_usage, builtin_merge_options);
|
|
|
|
|
2018-05-17 22:51:51 +00:00
|
|
|
if (!file_exists(git_path_merge_head(the_repository)))
|
2016-12-14 08:37:55 +00:00
|
|
|
die(_("There is no merge in progress (MERGE_HEAD missing)."));
|
|
|
|
|
|
|
|
/* Invoke 'git commit' */
|
|
|
|
ret = cmd_commit(nargc, nargv, prefix);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2022-11-19 13:07:30 +00:00
|
|
|
if (repo_read_index_unmerged(the_repository))
|
2010-11-09 21:49:58 +00:00
|
|
|
die_resolve_conflict("merge");
|
|
|
|
|
2018-05-17 22:51:51 +00:00
|
|
|
if (file_exists(git_path_merge_head(the_repository))) {
|
2010-11-09 21:49:58 +00:00
|
|
|
/*
|
|
|
|
* There is no unmerged entry, don't advise 'git
|
|
|
|
* add/rm <file>', just 'git commit'.
|
|
|
|
*/
|
2021-08-23 10:44:00 +00:00
|
|
|
if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("You have not concluded your merge (MERGE_HEAD exists).\n"
|
2014-08-30 19:56:01 +00:00
|
|
|
"Please, commit your changes before you merge."));
|
2010-11-09 21:49:58 +00:00
|
|
|
else
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("You have not concluded your merge (MERGE_HEAD exists)."));
|
2010-11-09 21:49:58 +00:00
|
|
|
}
|
2020-08-21 16:59:35 +00:00
|
|
|
if (ref_exists("CHERRY_PICK_HEAD")) {
|
2021-08-23 10:44:00 +00:00
|
|
|
if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
|
2011-04-10 19:34:05 +00:00
|
|
|
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
|
2014-08-30 19:56:01 +00:00
|
|
|
"Please, commit your changes before you merge."));
|
2011-02-20 04:12:27 +00:00
|
|
|
else
|
2011-04-10 19:34:05 +00:00
|
|
|
die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
|
2010-11-09 21:49:58 +00:00
|
|
|
}
|
2022-11-19 13:07:33 +00:00
|
|
|
resolve_undo_clear_index(&the_index);
|
2010-11-09 21:49:58 +00:00
|
|
|
|
2019-04-17 10:23:27 +00:00
|
|
|
if (option_edit < 0)
|
|
|
|
option_edit = default_edit_option();
|
|
|
|
|
|
|
|
cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
|
|
|
|
|
2008-11-15 00:14:24 +00:00
|
|
|
if (verbosity < 0)
|
|
|
|
show_diffstat = 0;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
if (squash) {
|
2013-07-02 14:47:57 +00:00
|
|
|
if (fast_forward == FF_NO)
|
2022-01-05 20:02:16 +00:00
|
|
|
die(_("options '%s' and '%s' cannot be used together"), "--squash", "--no-ff.");
|
2019-05-24 18:36:17 +00:00
|
|
|
if (option_commit > 0)
|
2022-01-05 20:02:16 +00:00
|
|
|
die(_("options '%s' and '%s' cannot be used together"), "--squash", "--commit.");
|
2019-05-24 18:36:17 +00:00
|
|
|
/*
|
|
|
|
* squash can now silently disable option_commit - this is not
|
|
|
|
* a problem as it is only overriding the default, not a user
|
|
|
|
* supplied option.
|
|
|
|
*/
|
2008-07-07 17:24:20 +00:00
|
|
|
option_commit = 0;
|
|
|
|
}
|
|
|
|
|
2019-05-24 18:36:17 +00:00
|
|
|
if (option_commit < 0)
|
|
|
|
option_commit = 1;
|
|
|
|
|
2015-04-23 20:01:44 +00:00
|
|
|
if (!argc) {
|
|
|
|
if (default_to_upstream)
|
|
|
|
argc = setup_with_upstream(&argv);
|
|
|
|
else
|
|
|
|
die(_("No commit specified and merge.defaultToUpstream not set."));
|
|
|
|
} else if (argc == 1 && !strcmp(argv[0], "-")) {
|
|
|
|
argv[0] = "@{-1}";
|
2011-04-07 22:57:57 +00:00
|
|
|
}
|
2015-04-23 20:01:44 +00:00
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!argc)
|
|
|
|
usage_with_options(builtin_merge_usage,
|
|
|
|
builtin_merge_options);
|
|
|
|
|
2015-04-23 20:46:44 +00:00
|
|
|
if (!head_commit) {
|
2008-07-07 17:24:20 +00:00
|
|
|
/*
|
|
|
|
* If the merged head is a valid one there is no reason
|
|
|
|
* to forbid "git merge" into a branch yet to be born.
|
|
|
|
* We do the same for "git pull".
|
|
|
|
*/
|
2017-02-21 23:47:28 +00:00
|
|
|
struct object_id *remote_head_oid;
|
2008-08-21 12:14:18 +00:00
|
|
|
if (squash)
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("Squash commit into empty head not supported yet"));
|
2013-07-02 14:47:57 +00:00
|
|
|
if (fast_forward == FF_NO)
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("Non-fast-forward commit does not make sense into "
|
|
|
|
"an empty head"));
|
2015-04-26 01:34:22 +00:00
|
|
|
remoteheads = collect_parents(head_commit, &head_subsumed,
|
|
|
|
argc, argv, NULL);
|
2016-03-21 19:01:43 +00:00
|
|
|
if (!remoteheads)
|
2011-02-22 23:41:59 +00:00
|
|
|
die(_("%s - not something we can merge"), argv[0]);
|
2015-04-23 20:56:34 +00:00
|
|
|
if (remoteheads->next)
|
|
|
|
die(_("Can merge only exactly one commit into empty head"));
|
2018-11-06 07:51:15 +00:00
|
|
|
|
|
|
|
if (verify_signatures)
|
gpg-interface: add minTrustLevel as a configuration option
Previously, signature verification for merge and pull operations checked
if the key had a trust-level of either TRUST_NEVER or TRUST_UNDEFINED in
verify_merge_signature(). If that was the case, the process die()d.
The other code paths that did signature verification relied entirely on
the return code from check_commit_signature(). And signatures made with
a good key, irregardless of its trust level, was considered valid by
check_commit_signature().
This difference in behavior might induce users to erroneously assume
that the trust level of a key in their keyring is always considered by
Git, even for operations where it is not (e.g. during a verify-commit or
verify-tag).
The way it worked was by gpg-interface.c storing the result from the
key/signature status *and* the lowest-two trust levels in the `result`
member of the signature_check structure (the last of these status lines
that were encountered got written to `result`). These are documented in
GPG under the subsection `General status codes` and `Key related`,
respectively [1].
The GPG documentation says the following on the TRUST_ status codes [1]:
"""
These are several similar status codes:
- TRUST_UNDEFINED <error_token>
- TRUST_NEVER <error_token>
- TRUST_MARGINAL [0 [<validation_model>]]
- TRUST_FULLY [0 [<validation_model>]]
- TRUST_ULTIMATE [0 [<validation_model>]]
For good signatures one of these status lines are emitted to
indicate the validity of the key used to create the signature.
The error token values are currently only emitted by gpgsm.
"""
My interpretation is that the trust level is conceptionally different
from the validity of the key and/or signature. That seems to also have
been the assumption of the old code in check_signature() where a result
of 'G' (as in GOODSIG) and 'U' (as in TRUST_NEVER or TRUST_UNDEFINED)
were both considered a success.
The two cases where a result of 'U' had special meaning were in
verify_merge_signature() (where this caused git to die()) and in
format_commit_one() (where it affected the output of the %G? format
specifier).
I think it makes sense to refactor the processing of TRUST_ status lines
such that users can configure a minimum trust level that is enforced
globally, rather than have individual parts of git (e.g. merge) do it
themselves (except for a grace period with backward compatibility).
I also think it makes sense to not store the trust level in the same
struct member as the key/signature status. While the presence of a
TRUST_ status code does imply that the signature is good (see the first
paragraph in the included snippet above), as far as I can tell, the
order of the status lines from GPG isn't well-defined; thus it would
seem plausible that the trust level could be overwritten with the
key/signature status if they were stored in the same member of the
signature_check structure.
This patch introduces a new configuration option: gpg.minTrustLevel. It
consolidates trust-level verification to gpg-interface.c and adds a new
`trust_level` member to the signature_check structure.
Backward-compatibility is maintained by introducing a special case in
verify_merge_signature() such that if no user-configurable
gpg.minTrustLevel is set, then the old behavior of rejecting
TRUST_UNDEFINED and TRUST_NEVER is enforced. If, on the other hand,
gpg.minTrustLevel is set, then that value overrides the old behavior.
Similarly, the %G? format specifier will continue show 'U' for
signatures made with a key that has a trust level of TRUST_UNDEFINED or
TRUST_NEVER, even though the 'U' character no longer exist in the
`result` member of the signature_check structure. A new format
specifier, %GT, is also introduced for users that want to show all
possible trust levels for a signature.
Another approach would have been to simply drop the trust-level
requirement in verify_merge_signature(). This would also have made the
behavior consistent with other parts of git that perform signature
verification. However, requiring a minimum trust level for signing keys
does seem to have a real-world use-case. For example, the build system
used by the Qubes OS project currently parses the raw output from
verify-tag in order to assert a minimum trust level for keys used to
sign git tags [2].
[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/doc/DETAILS;h=bd00006e933ac56719b1edd2478ecd79273eae72;hb=refs/heads/master
[2] https://github.com/QubesOS/qubes-builder/blob/9674c1991deef45b1a1b1c71fddfab14ba50dccf/scripts/verify-git-tag#L43
Signed-off-by: Hans Jerry Illikainen <hji@dyntopia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-27 13:55:57 +00:00
|
|
|
verify_merge_signature(remoteheads->item, verbosity,
|
|
|
|
check_trust_level);
|
2018-11-06 07:51:15 +00:00
|
|
|
|
2017-02-21 23:47:28 +00:00
|
|
|
remote_head_oid = &remoteheads->item->object.oid;
|
2022-10-30 11:42:59 +00:00
|
|
|
read_empty(remote_head_oid);
|
2017-10-15 22:06:51 +00:00
|
|
|
update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
|
|
|
|
UPDATE_REFS_DIE_ON_ERR);
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
2015-04-23 20:46:44 +00:00
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2015-04-23 20:46:44 +00:00
|
|
|
/*
|
2015-03-26 05:00:48 +00:00
|
|
|
* All the rest are the commits being merged; prepare
|
|
|
|
* the standard merge summary message to be appended
|
|
|
|
* to the given message.
|
2015-04-23 20:46:44 +00:00
|
|
|
*/
|
2015-03-26 05:00:48 +00:00
|
|
|
remoteheads = collect_parents(head_commit, &head_subsumed,
|
|
|
|
argc, argv, &merge_msg);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2011-09-17 11:57:44 +00:00
|
|
|
if (!head_commit || !argc)
|
2008-07-07 17:24:20 +00:00
|
|
|
usage_with_options(builtin_merge_usage,
|
|
|
|
builtin_merge_options);
|
|
|
|
|
2013-03-31 16:02:24 +00:00
|
|
|
if (verify_signatures) {
|
|
|
|
for (p = remoteheads; p; p = p->next) {
|
gpg-interface: add minTrustLevel as a configuration option
Previously, signature verification for merge and pull operations checked
if the key had a trust-level of either TRUST_NEVER or TRUST_UNDEFINED in
verify_merge_signature(). If that was the case, the process die()d.
The other code paths that did signature verification relied entirely on
the return code from check_commit_signature(). And signatures made with
a good key, irregardless of its trust level, was considered valid by
check_commit_signature().
This difference in behavior might induce users to erroneously assume
that the trust level of a key in their keyring is always considered by
Git, even for operations where it is not (e.g. during a verify-commit or
verify-tag).
The way it worked was by gpg-interface.c storing the result from the
key/signature status *and* the lowest-two trust levels in the `result`
member of the signature_check structure (the last of these status lines
that were encountered got written to `result`). These are documented in
GPG under the subsection `General status codes` and `Key related`,
respectively [1].
The GPG documentation says the following on the TRUST_ status codes [1]:
"""
These are several similar status codes:
- TRUST_UNDEFINED <error_token>
- TRUST_NEVER <error_token>
- TRUST_MARGINAL [0 [<validation_model>]]
- TRUST_FULLY [0 [<validation_model>]]
- TRUST_ULTIMATE [0 [<validation_model>]]
For good signatures one of these status lines are emitted to
indicate the validity of the key used to create the signature.
The error token values are currently only emitted by gpgsm.
"""
My interpretation is that the trust level is conceptionally different
from the validity of the key and/or signature. That seems to also have
been the assumption of the old code in check_signature() where a result
of 'G' (as in GOODSIG) and 'U' (as in TRUST_NEVER or TRUST_UNDEFINED)
were both considered a success.
The two cases where a result of 'U' had special meaning were in
verify_merge_signature() (where this caused git to die()) and in
format_commit_one() (where it affected the output of the %G? format
specifier).
I think it makes sense to refactor the processing of TRUST_ status lines
such that users can configure a minimum trust level that is enforced
globally, rather than have individual parts of git (e.g. merge) do it
themselves (except for a grace period with backward compatibility).
I also think it makes sense to not store the trust level in the same
struct member as the key/signature status. While the presence of a
TRUST_ status code does imply that the signature is good (see the first
paragraph in the included snippet above), as far as I can tell, the
order of the status lines from GPG isn't well-defined; thus it would
seem plausible that the trust level could be overwritten with the
key/signature status if they were stored in the same member of the
signature_check structure.
This patch introduces a new configuration option: gpg.minTrustLevel. It
consolidates trust-level verification to gpg-interface.c and adds a new
`trust_level` member to the signature_check structure.
Backward-compatibility is maintained by introducing a special case in
verify_merge_signature() such that if no user-configurable
gpg.minTrustLevel is set, then the old behavior of rejecting
TRUST_UNDEFINED and TRUST_NEVER is enforced. If, on the other hand,
gpg.minTrustLevel is set, then that value overrides the old behavior.
Similarly, the %G? format specifier will continue show 'U' for
signatures made with a key that has a trust level of TRUST_UNDEFINED or
TRUST_NEVER, even though the 'U' character no longer exist in the
`result` member of the signature_check structure. A new format
specifier, %GT, is also introduced for users that want to show all
possible trust levels for a signature.
Another approach would have been to simply drop the trust-level
requirement in verify_merge_signature(). This would also have made the
behavior consistent with other parts of git that perform signature
verification. However, requiring a minimum trust level for signing keys
does seem to have a real-world use-case. For example, the build system
used by the Qubes OS project currently parses the raw output from
verify-tag in order to assert a minimum trust level for keys used to
sign git tags [2].
[1] https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/doc/DETAILS;h=bd00006e933ac56719b1edd2478ecd79273eae72;hb=refs/heads/master
[2] https://github.com/QubesOS/qubes-builder/blob/9674c1991deef45b1a1b1c71fddfab14ba50dccf/scripts/verify-git-tag#L43
Signed-off-by: Hans Jerry Illikainen <hji@dyntopia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-12-27 13:55:57 +00:00
|
|
|
verify_merge_signature(p->item, verbosity,
|
|
|
|
check_trust_level);
|
2013-03-31 16:02:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_addstr(&buf, "merge");
|
2012-04-17 18:31:10 +00:00
|
|
|
for (p = remoteheads; p; p = p->next)
|
|
|
|
strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
|
2008-07-07 17:24:20 +00:00
|
|
|
setenv("GIT_REFLOG_ACTION", buf.buf, 0);
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
|
2012-04-17 18:31:10 +00:00
|
|
|
for (p = remoteheads; p; p = p->next) {
|
|
|
|
struct commit *commit = p->item;
|
2011-11-07 21:26:22 +00:00
|
|
|
strbuf_addf(&buf, "GITHEAD_%s",
|
2016-06-24 23:09:22 +00:00
|
|
|
oid_to_hex(&commit->object.oid));
|
2012-04-17 18:31:10 +00:00
|
|
|
setenv(buf.buf, merge_remote_util(commit)->name, 1);
|
2008-07-07 17:24:20 +00:00
|
|
|
strbuf_reset(&buf);
|
2018-02-14 18:18:55 +00:00
|
|
|
if (fast_forward != FF_ONLY && merging_a_throwaway_tag(commit))
|
2013-07-02 14:47:57 +00:00
|
|
|
fast_forward = FF_NO;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
Change default merge backend from recursive to ort
There are a few reasons to switch the default:
* Correctness
* Extensibility
* Performance
I'll provide some summaries about each.
=== Correctness ===
The original impetus for a new merge backend was to fix issues that were
difficult to fix within recursive's design. The success with this goal
is perhaps most easily demonstrated by running the following:
$ git grep -2 KNOWN_FAILURE t/ | grep -A 4 GIT_TEST_MERGE_ALGORITHM
$ git grep test_expect_merge_algorithm.failure.success t/
$ git grep test_expect_merge_algorithm.success.failure t/
In order, these greps show:
* Seven sets of submodule tests (10 total tests) that fail with
recursive but succeed with ort
* 22 other tests that fail with recursive, but succeed with ort
* 0 tests that pass with recursive, but fail with ort
=== Extensibility ===
Being able to perform merges without touching the working tree or index
makes it possible to create new features that were difficult with the
old backend:
* Merging, cherry-picking, rebasing, reverting in bare repositories...
or just on branches that aren't checked out.
* `git diff AUTO_MERGE` -- ability to see what changes the user has
made to resolve conflicts so far (see commit 5291828df8 ("merge-ort:
write $GIT_DIR/AUTO_MERGE whenever we hit a conflict", 2021-03-20)
* A --remerge-diff option for log/show, used to show diffs for merges
that display the difference between what an automatic merge would
have created and what was recorded in the merge. (This option will
often result in an empty diff because many merges are clean, but for
the non-clean ones it will show how conflicts were fixed including
the removal of conflict markers, and also show additional changes
made outside of conflict regions to e.g. fix semantic conflicts.)
* A --remerge-diff-only option for log/show, similar to --remerge-diff
but also showing how cherry-picks or reverts differed from what an
automatic cherry-pick or revert would provide.
The last three have been implemented already (though only one has been
submitted upstream so far; the others were waiting for performance work
to complete), and I still plan to implement the first one.
=== Performance ===
I'll quote from the summary of my final optimization for merge-ort
(while fixing the testcase name from 'no-renames' to 'few-renames'):
Timings
Infinite
merge- merge- Parallelism
recursive recursive of rename merge-ort
v2.30.0 current detection current
---------- --------- ----------- ---------
few-renames: 18.912 s 18.030 s 11.699 s 198.3 ms
mega-renames: 5964.031 s 361.281 s 203.886 s 661.8 ms
just-one-mega: 149.583 s 11.009 s 7.553 s 264.6 ms
Speedup factors
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
few-renames: 1 1.05 1.6 95
mega-renames: 1 16.5 29 9012
just-one-mega: 1 13.6 20 565
And, for partial clone users:
Factor reduction in number of objects needed
Infinite
merge- merge- Parallelism
recursive recursive of rename
v2.30.0 current detection merge-ort
---------- --------- ----------- ---------
mega-renames: 1 1 1 181.3
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-08-04 05:38:01 +00:00
|
|
|
if (!use_strategies && !pull_twohead &&
|
|
|
|
remoteheads && !remoteheads->next) {
|
|
|
|
char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
|
|
|
|
if (default_strategy)
|
|
|
|
append_strategy(get_strategy(default_strategy));
|
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
if (!use_strategies) {
|
2012-04-17 19:22:26 +00:00
|
|
|
if (!remoteheads)
|
|
|
|
; /* already up-to-date */
|
|
|
|
else if (!remoteheads->next)
|
2008-07-07 17:24:20 +00:00
|
|
|
add_strategies(pull_twohead, DEFAULT_TWOHEAD);
|
|
|
|
else
|
|
|
|
add_strategies(pull_octopus, DEFAULT_OCTOPUS);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < use_strategies_nr; i++) {
|
|
|
|
if (use_strategies[i]->attr & NO_FAST_FORWARD)
|
2013-07-02 14:47:57 +00:00
|
|
|
fast_forward = FF_NO;
|
2008-07-07 17:24:20 +00:00
|
|
|
if (use_strategies[i]->attr & NO_TRIVIAL)
|
|
|
|
allow_trivial = 0;
|
|
|
|
}
|
|
|
|
|
2012-04-17 19:22:26 +00:00
|
|
|
if (!remoteheads)
|
|
|
|
; /* already up-to-date */
|
|
|
|
else if (!remoteheads->next)
|
2023-03-28 13:58:47 +00:00
|
|
|
common = repo_get_merge_bases(the_repository, head_commit,
|
|
|
|
remoteheads->item);
|
2008-07-07 17:24:20 +00:00
|
|
|
else {
|
|
|
|
struct commit_list *list = remoteheads;
|
2011-09-17 11:57:44 +00:00
|
|
|
commit_list_insert(head_commit, &list);
|
2008-07-07 17:24:20 +00:00
|
|
|
common = get_octopus_merge_bases(list);
|
|
|
|
free(list);
|
|
|
|
}
|
|
|
|
|
2017-10-15 22:06:51 +00:00
|
|
|
update_ref("updating ORIG_HEAD", "ORIG_HEAD",
|
|
|
|
&head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
merge: refuse to create too cool a merge by default
While it makes sense to allow merging unrelated histories of two
projects that started independently into one, in the way "gitk" was
merged to "git" itself aka "the coolest merge ever", such a merge is
still an unusual event. Worse, if somebody creates an independent
history by starting from a tarball of an established project and
sends a pull request to the original project, "git merge" however
happily creates such a merge without any sign of something unusual
is happening.
Teach "git merge" to refuse to create such a merge by default,
unless the user passes a new "--allow-unrelated-histories" option to
tell it that the user is aware that two unrelated projects are
merged.
Because such a "two project merge" is a rare event, a configuration
option to always allow such a merge is not added.
We could add the same option to "git pull" and have it passed
through to underlying "git merge". I do not have a fundamental
opposition against such a feature, but this commit does not do so
and instead leaves it as low-hanging fruit for others, because such
a "two project merge" would be done after fetching the other project
into some location in the working tree of an existing project and
making sure how well they fit together, it is sufficient to allow a
local merge without such an option pass-through from "git pull" to
"git merge". Many tests that are updated by this patch does the
pass-through manually by turning:
git pull something
into its equivalent:
git fetch something &&
git merge --allow-unrelated-histories FETCH_HEAD
If somebody is inclined to add such an option, updated tests in this
change need to be adjusted back to:
git pull --allow-unrelated-histories something
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-18 20:21:09 +00:00
|
|
|
if (remoteheads && !common) {
|
|
|
|
/* No common ancestors found. */
|
|
|
|
if (!allow_unrelated_histories)
|
|
|
|
die(_("refusing to merge unrelated histories"));
|
|
|
|
/* otherwise, we need a real merge. */
|
|
|
|
} else if (!remoteheads ||
|
2012-04-17 19:22:26 +00:00
|
|
|
(!remoteheads->next && !common->next &&
|
|
|
|
common->item == remoteheads->item)) {
|
2008-07-07 17:24:20 +00:00
|
|
|
/*
|
|
|
|
* If head can reach all the merge then we are up to date.
|
|
|
|
* but first the most common case of merging one remote.
|
|
|
|
*/
|
2021-05-02 05:14:23 +00:00
|
|
|
finish_up_to_date();
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
2013-07-02 14:47:57 +00:00
|
|
|
} else if (fast_forward != FF_NO && !remoteheads->next &&
|
2008-07-07 17:24:20 +00:00
|
|
|
!common->next &&
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-28 21:22:40 +00:00
|
|
|
oideq(&common->item->object.oid, &head_commit->object.oid)) {
|
2008-07-07 17:24:20 +00:00
|
|
|
/* Again the most common case of merging one remote. */
|
2023-02-06 23:07:48 +00:00
|
|
|
const char *msg = have_message ?
|
|
|
|
"Fast-forward (no commit created; -m option ignored)" :
|
|
|
|
"Fast-forward";
|
2011-11-07 21:26:22 +00:00
|
|
|
struct commit *commit;
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2015-09-24 21:08:03 +00:00
|
|
|
if (verbosity >= 0) {
|
2016-10-20 06:19:19 +00:00
|
|
|
printf(_("Updating %s..%s\n"),
|
2023-03-28 13:58:46 +00:00
|
|
|
repo_find_unique_abbrev(the_repository, &head_commit->object.oid,
|
|
|
|
DEFAULT_ABBREV),
|
|
|
|
repo_find_unique_abbrev(the_repository, &remoteheads->item->object.oid,
|
|
|
|
DEFAULT_ABBREV));
|
2015-09-24 21:08:03 +00:00
|
|
|
}
|
2011-11-07 21:26:22 +00:00
|
|
|
commit = remoteheads->item;
|
2011-12-09 21:37:14 +00:00
|
|
|
if (!commit) {
|
2011-11-13 10:22:15 +00:00
|
|
|
ret = 1;
|
|
|
|
goto done;
|
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2020-04-07 14:28:07 +00:00
|
|
|
if (autostash)
|
|
|
|
create_autostash(the_repository,
|
2022-01-26 13:05:44 +00:00
|
|
|
git_path_merge_autostash(the_repository));
|
2018-09-21 15:57:29 +00:00
|
|
|
if (checkout_fast_forward(the_repository,
|
|
|
|
&head_commit->object.oid,
|
2017-05-06 22:10:33 +00:00
|
|
|
&commit->object.oid,
|
2012-10-26 15:53:49 +00:00
|
|
|
overwrite_ignore)) {
|
2021-07-23 12:14:29 +00:00
|
|
|
apply_autostash(git_path_merge_autostash(the_repository));
|
2011-11-13 10:22:15 +00:00
|
|
|
ret = 1;
|
|
|
|
goto done;
|
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2023-02-06 23:07:48 +00:00
|
|
|
finish(head_commit, remoteheads, &commit->object.oid, msg);
|
2019-05-09 10:10:27 +00:00
|
|
|
remove_merge_branch_state(the_repository);
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
2008-07-07 17:24:20 +00:00
|
|
|
} else if (!remoteheads->next && common->next)
|
|
|
|
;
|
|
|
|
/*
|
2009-10-24 08:31:32 +00:00
|
|
|
* We are not doing octopus and not fast-forward. Need
|
2008-07-07 17:24:20 +00:00
|
|
|
* a real merge.
|
|
|
|
*/
|
|
|
|
else if (!remoteheads->next && !common->next && option_commit) {
|
|
|
|
/*
|
2009-10-24 08:31:32 +00:00
|
|
|
* We are not doing octopus, not fast-forward, and have
|
2008-07-07 17:24:20 +00:00
|
|
|
* only one common.
|
|
|
|
*/
|
2022-11-19 13:07:38 +00:00
|
|
|
refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
|
2013-07-02 14:47:57 +00:00
|
|
|
if (allow_trivial && fast_forward != FF_ONLY) {
|
2022-07-23 01:53:13 +00:00
|
|
|
/*
|
|
|
|
* Must first ensure that index matches HEAD before
|
|
|
|
* attempting a trivial merge.
|
|
|
|
*/
|
2023-03-28 13:58:48 +00:00
|
|
|
struct tree *head_tree = repo_get_commit_tree(the_repository,
|
|
|
|
head_commit);
|
2022-07-23 01:53:13 +00:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (repo_index_has_changes(the_repository, head_tree,
|
|
|
|
&sb)) {
|
|
|
|
error(_("Your local changes to the following files would be overwritten by merge:\n %s"),
|
|
|
|
sb.buf);
|
|
|
|
strbuf_release(&sb);
|
2023-02-06 23:07:49 +00:00
|
|
|
ret = 2;
|
|
|
|
goto done;
|
2022-07-23 01:53:13 +00:00
|
|
|
}
|
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
/* See if it is really trivial. */
|
2012-05-24 23:28:40 +00:00
|
|
|
git_committer_info(IDENT_STRICT);
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Trying really trivial in-index merge...\n"));
|
2017-02-21 23:47:28 +00:00
|
|
|
if (!read_tree_trivial(&common->item->object.oid,
|
|
|
|
&head_commit->object.oid,
|
|
|
|
&remoteheads->item->object.oid)) {
|
2012-04-16 23:15:13 +00:00
|
|
|
ret = merge_trivial(head_commit, remoteheads);
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Nope.\n"));
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* An octopus. If we can reach all the remote we are up
|
|
|
|
* to date.
|
|
|
|
*/
|
|
|
|
int up_to_date = 1;
|
|
|
|
struct commit_list *j;
|
|
|
|
|
|
|
|
for (j = remoteheads; j; j = j->next) {
|
|
|
|
struct commit_list *common_one;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here we *have* to calculate the individual
|
|
|
|
* merge_bases again, otherwise "git merge HEAD^
|
|
|
|
* HEAD^^" would be missed.
|
|
|
|
*/
|
2023-03-28 13:58:47 +00:00
|
|
|
common_one = repo_get_merge_bases(the_repository,
|
|
|
|
head_commit,
|
|
|
|
j->item);
|
2018-08-28 21:22:48 +00:00
|
|
|
if (!oideq(&common_one->item->object.oid, &j->item->object.oid)) {
|
2008-07-07 17:24:20 +00:00
|
|
|
up_to_date = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (up_to_date) {
|
2021-05-02 05:14:23 +00:00
|
|
|
finish_up_to_date();
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-02 14:47:57 +00:00
|
|
|
if (fast_forward == FF_ONLY)
|
2021-07-21 01:42:19 +00:00
|
|
|
die_ff_impossible();
|
2009-10-29 22:08:31 +00:00
|
|
|
|
2020-04-07 14:28:07 +00:00
|
|
|
if (autostash)
|
|
|
|
create_autostash(the_repository,
|
2022-01-26 13:05:44 +00:00
|
|
|
git_path_merge_autostash(the_repository));
|
2020-04-07 14:28:07 +00:00
|
|
|
|
2008-07-07 17:24:20 +00:00
|
|
|
/* We are going to make a new commit. */
|
2012-05-24 23:28:40 +00:00
|
|
|
git_committer_info(IDENT_STRICT);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point, we need a real merge. No matter what strategy
|
|
|
|
* we use, it would operate on the index, possibly affecting the
|
|
|
|
* working tree, and when resolved cleanly, have the desired
|
|
|
|
* tree in the index -- this means that the index must be in
|
|
|
|
* sync with the head commit. The strategies are responsible
|
|
|
|
* to ensure this.
|
merge: ensure we can actually restore pre-merge state
Merge strategies can:
* succeed with a clean merge
* succeed with a conflicted merge
* fail to handle the given type of merge
If one is thinking in terms of automatic mergeability, they would use
the word "fail" instead of "succeed" for the second bullet, but I am
focusing here on ability of the merge strategy to handle the given
inputs, not on whether the given inputs are mergeable. The third
category is about the merge strategy failing to know how to handle the
given data; examples include:
* Passing more than 2 branches to 'recursive' or 'ort'
* Passing 2 or fewer branches to 'octopus'
* Trying to do more complicated merges with 'resolve' (I believe
directory/file conflicts will cause it to bail.)
* Octopus running into a merge conflict for any branch OTHER than
the final one (see the "exit 2" codepath of commit 98efc8f3d8
("octopus: allow manual resolve on the last round.", 2006-01-13))
That final one is particularly interesting, because it shows that the
merge strategy can muck with the index and working tree, and THEN bail
and say "sorry, this strategy cannot handle this type of merge; use
something else".
Further, we do not currently expect the individual strategies to clean
up after themselves, but instead expect builtin/merge.c to do so. For
it to be able to, it needs to save the state before trying the merge
strategy so it can have something to restore to. Therefore, remove the
shortcut bypassing the save_state() call.
There is another bug on the restore_state() side of things, so no
testcase will be added until the next commit when we have addressed that
issue as well.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:53:17 +00:00
|
|
|
*
|
|
|
|
* Stash away the local changes so that we can try more than one
|
|
|
|
* and/or recover from merge strategies bailing while leaving the
|
|
|
|
* index and working tree polluted.
|
2008-07-07 17:24:20 +00:00
|
|
|
*/
|
merge: ensure we can actually restore pre-merge state
Merge strategies can:
* succeed with a clean merge
* succeed with a conflicted merge
* fail to handle the given type of merge
If one is thinking in terms of automatic mergeability, they would use
the word "fail" instead of "succeed" for the second bullet, but I am
focusing here on ability of the merge strategy to handle the given
inputs, not on whether the given inputs are mergeable. The third
category is about the merge strategy failing to know how to handle the
given data; examples include:
* Passing more than 2 branches to 'recursive' or 'ort'
* Passing 2 or fewer branches to 'octopus'
* Trying to do more complicated merges with 'resolve' (I believe
directory/file conflicts will cause it to bail.)
* Octopus running into a merge conflict for any branch OTHER than
the final one (see the "exit 2" codepath of commit 98efc8f3d8
("octopus: allow manual resolve on the last round.", 2006-01-13))
That final one is particularly interesting, because it shows that the
merge strategy can muck with the index and working tree, and THEN bail
and say "sorry, this strategy cannot handle this type of merge; use
something else".
Further, we do not currently expect the individual strategies to clean
up after themselves, but instead expect builtin/merge.c to do so. For
it to be able to, it needs to save the state before trying the merge
strategy so it can have something to restore to. Therefore, remove the
shortcut bypassing the save_state() call.
There is another bug on the restore_state() side of things, so no
testcase will be added until the next commit when we have addressed that
issue as well.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-07-23 01:53:17 +00:00
|
|
|
if (save_state(&stash))
|
2017-02-21 23:47:28 +00:00
|
|
|
oidclr(&stash);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
merge: cleanup confusing logic for handling successful merges
builtin/merge.c has a loop over the specified strategies, where if they
all fail with conflicts, it picks the one with the least number of
conflicts.
In the codepath that finds a successful merge, if an automatic commit
was wanted, the code breaks out of the above loop, which makes sense.
However, if the user requested there be no automatic commit, the loop
would continue. That seems weird; --no-commit should not affect the
choice of merge strategy, but the code as written makes one think it
does. However, since the loop itself embeds "!merge_was_ok" as a
condition on continuing to loop, it actually would also exit early if
--no-commit was specified, it just exited from a different location.
Restructure the code slightly to make it clear that the loop will
immediately exit whenever we find a merge strategy that is successful.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-23 02:42:20 +00:00
|
|
|
for (i = 0; i < use_strategies_nr; i++) {
|
2019-07-09 03:15:59 +00:00
|
|
|
int ret, cnt;
|
2008-07-07 17:24:20 +00:00
|
|
|
if (i) {
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Rewinding the tree to pristine...\n"));
|
2017-02-21 23:47:28 +00:00
|
|
|
restore_state(&head_commit->object.oid, &stash);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
if (use_strategies_nr != 1)
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Trying merge strategy %s...\n"),
|
2008-07-07 17:24:20 +00:00
|
|
|
use_strategies[i]->name);
|
|
|
|
/*
|
|
|
|
* Remember which strategy left the state in the working
|
|
|
|
* tree.
|
|
|
|
*/
|
|
|
|
wt_strategy = use_strategies[i]->name;
|
|
|
|
|
2022-08-23 02:42:21 +00:00
|
|
|
ret = try_merge_strategy(wt_strategy,
|
2012-04-16 23:15:13 +00:00
|
|
|
common, remoteheads,
|
2015-03-26 05:00:48 +00:00
|
|
|
head_commit);
|
2019-07-09 03:15:59 +00:00
|
|
|
/*
|
|
|
|
* The backend exits with 1 when conflicts are
|
|
|
|
* left to be resolved, with 2 when it does not
|
|
|
|
* handle the given merge at all.
|
|
|
|
*/
|
|
|
|
if (ret < 2) {
|
|
|
|
if (!ret) {
|
merge: cleanup confusing logic for handling successful merges
builtin/merge.c has a loop over the specified strategies, where if they
all fail with conflicts, it picks the one with the least number of
conflicts.
In the codepath that finds a successful merge, if an automatic commit
was wanted, the code breaks out of the above loop, which makes sense.
However, if the user requested there be no automatic commit, the loop
would continue. That seems weird; --no-commit should not affect the
choice of merge strategy, but the code as written makes one think it
does. However, since the loop itself embeds "!merge_was_ok" as a
condition on continuing to loop, it actually would also exit early if
--no-commit was specified, it just exited from a different location.
Restructure the code slightly to make it clear that the loop will
immediately exit whenever we find a merge strategy that is successful.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-23 02:42:20 +00:00
|
|
|
/*
|
|
|
|
* This strategy worked; no point in trying
|
|
|
|
* another.
|
|
|
|
*/
|
2019-07-09 03:15:59 +00:00
|
|
|
merge_was_ok = 1;
|
2022-08-23 02:42:21 +00:00
|
|
|
best_strategy = wt_strategy;
|
merge: cleanup confusing logic for handling successful merges
builtin/merge.c has a loop over the specified strategies, where if they
all fail with conflicts, it picks the one with the least number of
conflicts.
In the codepath that finds a successful merge, if an automatic commit
was wanted, the code breaks out of the above loop, which makes sense.
However, if the user requested there be no automatic commit, the loop
would continue. That seems weird; --no-commit should not affect the
choice of merge strategy, but the code as written makes one think it
does. However, since the loop itself embeds "!merge_was_ok" as a
condition on continuing to loop, it actually would also exit early if
--no-commit was specified, it just exited from a different location.
Restructure the code slightly to make it clear that the loop will
immediately exit whenever we find a merge strategy that is successful.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-23 02:42:20 +00:00
|
|
|
break;
|
2019-07-09 03:15:59 +00:00
|
|
|
}
|
2020-05-19 13:05:35 +00:00
|
|
|
cnt = (use_strategies_nr > 1) ? evaluate_result() : 0;
|
2019-07-09 03:15:59 +00:00
|
|
|
if (best_cnt <= 0 || cnt <= best_cnt) {
|
2022-08-23 02:42:21 +00:00
|
|
|
best_strategy = wt_strategy;
|
2019-07-09 03:15:59 +00:00
|
|
|
best_cnt = cnt;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a resulting tree, that means the strategy module
|
|
|
|
* auto resolved the merge cleanly.
|
|
|
|
*/
|
merge: cleanup confusing logic for handling successful merges
builtin/merge.c has a loop over the specified strategies, where if they
all fail with conflicts, it picks the one with the least number of
conflicts.
In the codepath that finds a successful merge, if an automatic commit
was wanted, the code breaks out of the above loop, which makes sense.
However, if the user requested there be no automatic commit, the loop
would continue. That seems weird; --no-commit should not affect the
choice of merge strategy, but the code as written makes one think it
does. However, since the loop itself embeds "!merge_was_ok" as a
condition on continuing to loop, it actually would also exit early if
--no-commit was specified, it just exited from a different location.
Restructure the code slightly to make it clear that the loop will
immediately exit whenever we find a merge strategy that is successful.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-08-23 02:42:20 +00:00
|
|
|
if (merge_was_ok && option_commit) {
|
|
|
|
automerge_was_ok = 1;
|
2012-04-17 19:22:26 +00:00
|
|
|
ret = finish_automerge(head_commit, head_subsumed,
|
|
|
|
common, remoteheads,
|
2017-02-21 23:47:28 +00:00
|
|
|
&result_tree, wt_strategy);
|
2011-11-13 10:22:15 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2008-07-07 17:24:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Pick the result from the best strategy and have the user fix
|
|
|
|
* it up.
|
|
|
|
*/
|
|
|
|
if (!best_strategy) {
|
2017-02-21 23:47:28 +00:00
|
|
|
restore_state(&head_commit->object.oid, &stash);
|
2008-07-07 17:24:20 +00:00
|
|
|
if (use_strategies_nr > 1)
|
|
|
|
fprintf(stderr,
|
2011-02-22 23:41:59 +00:00
|
|
|
_("No merge strategy handled the merge.\n"));
|
2008-07-07 17:24:20 +00:00
|
|
|
else
|
2011-02-22 23:41:59 +00:00
|
|
|
fprintf(stderr, _("Merge with strategy %s failed.\n"),
|
2008-07-07 17:24:20 +00:00
|
|
|
use_strategies[0]->name);
|
merge: apply autostash if merge strategy fails
Since 'git merge' learned '--autostash' in a03b55530a (merge: teach
--autostash option, 2020-04-07), 'cmd_merge', once it is determined that
we have to create a merge commit, calls 'create_autostash' if
'--autostash' is given.
As explained in a03b55530a, and made more abvious by the tests added in
that commit, the autostash is then applied if the merge succeeds, either
directly or by committing (after conflict resolution or if '--no-commit'
was given), or if the merge is aborted with 'git merge --abort'. In some
other cases, like the user calling 'git reset --merge' or 'git merge
--quit', the autostash is not applied, but saved in the stash list.
However, there exists a scenario that creates an autostash but does not
apply nor save it to the stash list: if the chosen merge strategy
completely fails to handle the merge, i.e. 'try_merge_strategy' returns
2.
Apply the autostash in that case also. An easy way to test that is to
try to merge more than two commits but explicitely ask for the 'recursive'
merge strategy.
Signed-off-by: Philippe Blain <levraiphilippeblain@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-07-23 12:14:30 +00:00
|
|
|
apply_autostash(git_path_merge_autostash(the_repository));
|
2011-11-13 10:22:15 +00:00
|
|
|
ret = 2;
|
|
|
|
goto done;
|
2008-07-07 17:24:20 +00:00
|
|
|
} else if (best_strategy == wt_strategy)
|
|
|
|
; /* We already have its result in the working tree. */
|
|
|
|
else {
|
2011-02-22 23:41:59 +00:00
|
|
|
printf(_("Rewinding the tree to pristine...\n"));
|
2017-02-21 23:47:28 +00:00
|
|
|
restore_state(&head_commit->object.oid, &stash);
|
2021-07-23 12:14:27 +00:00
|
|
|
printf(_("Using the %s strategy to prepare resolving by hand.\n"),
|
2008-07-07 17:24:20 +00:00
|
|
|
best_strategy);
|
2012-04-16 23:15:13 +00:00
|
|
|
try_merge_strategy(best_strategy, common, remoteheads,
|
2015-03-26 05:00:48 +00:00
|
|
|
head_commit);
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|
|
|
|
|
2020-04-16 20:14:03 +00:00
|
|
|
if (squash) {
|
2012-04-16 23:15:13 +00:00
|
|
|
finish(head_commit, remoteheads, NULL, NULL);
|
2020-04-16 20:14:03 +00:00
|
|
|
|
|
|
|
git_test_write_commit_graph_or_die();
|
|
|
|
} else
|
2012-04-16 23:15:13 +00:00
|
|
|
write_merge_state(remoteheads);
|
2008-07-07 17:24:20 +00:00
|
|
|
|
2011-11-13 10:22:15 +00:00
|
|
|
if (merge_was_ok)
|
2011-02-22 23:41:59 +00:00
|
|
|
fprintf(stderr, _("Automatic merge went well; "
|
|
|
|
"stopped before committing as requested\n"));
|
2011-11-13 10:22:15 +00:00
|
|
|
else
|
2014-10-24 18:27:22 +00:00
|
|
|
ret = suggest_conflicts();
|
2022-08-23 02:42:19 +00:00
|
|
|
if (autostash)
|
|
|
|
printf(_("When finished, apply stashed changes with `git stash pop`\n"));
|
2011-11-13 10:22:15 +00:00
|
|
|
|
|
|
|
done:
|
2022-01-20 07:47:15 +00:00
|
|
|
if (!automerge_was_ok) {
|
|
|
|
free_commit_list(common);
|
|
|
|
free_commit_list(remoteheads);
|
|
|
|
}
|
2021-10-07 10:01:37 +00:00
|
|
|
strbuf_release(&buf);
|
2011-12-13 14:17:48 +00:00
|
|
|
free(branch_to_free);
|
2022-11-08 18:17:38 +00:00
|
|
|
discard_index(&the_index);
|
2011-11-13 10:22:15 +00:00
|
|
|
return ret;
|
2008-07-07 17:24:20 +00:00
|
|
|
}
|