The general answer is given here: How do I make git merge's default be --no-ff --no-commit?
But how to enforce this only for remote branches ? Is there a way to do this?
The general answer is given here: How do I make git merge's default be --no-ff --no-commit?
But how to enforce this only for remote branches ? Is there a way to do this?
No, or at least, not as far as I know; and see caveats below: I suspect what you want to do has sufficiently limited usefulness that you may be going about it the wrong way. (See What is the XY problem?)
(I also think VonC's answer to a related question is worth reading before attempting to use this answer.)
If you do your merges "manually" you can always write your own script to do it. (This means avoiding git pull
in favor of git fetch
for instance: run git fetch
, then your do-merge
script, whatever you call it.)
So: how can you write a script that mimics git merge
? This depends on how thorough you want to be, of course. You can use git rev-parse --parseopt
to parse arguments for you (for instance, see the git-rebase
script plus the git-sh-setup
script, both in the git-core
directory, often /usr/libexec
or /usr/local/libexec
, although installations vary).
You must also decide whether to use merge.defaultToUpstream
if there are no commit
arguments, and how thorough you want to be about detecting in-progress merges, modified work directories before a merge starts, and so on.
In any case, let's say you've gotten to the point in the script where you're ready to run the "real" git merge
command, and you want to add --no-ff --no-commit
if and only if (1) the arguments to the script do not override this, and (2) a "commit" to be merged, whether given directly or implied by merge.defaultToUpstream
, names a "remote branch". How do you decide that the commit is a "remote branch"?
The simplest test is to run git rev-parse --symbolic-full-name
on it. If the resulting name starts with refs/remotes/
, the name is symbolic and names a remote branch:
name_is_remote_branch() {
local full
full=$(git rev-parse --symbolic-full-name $1)
case $full in
refs/remotes/*) return 0;;
*) return 1;;
esac
}
The above shell function can be used as, e.g.:
if name_is_remote_branch origin/master; then
echo seems to work
else
echo oops
fi
or (shorter, and still just for demonstration):
name_is_remote_branch master || echo ok # master should not be "remote branch"
(In other words, just like any "real command", the function returns 0 for success/true, and nonzero for "failure"/false, so boolean_test && if_true
and boolean_test || if_false
are useable shorthand.)
Now you can use the little shell function to test a symbolic reference given to your merge script, provided of course that condition (1) ("arguments to script do not override") is also met.
Merges actually work by commit IDs, which are permanent; but your automatic control knob is based on commit name, which is changeable.
What happens if we apply this test to a raw SHA-1 ID?
$ git log -1 --decorate --oneline
676699a (origin/master, master) commit subject here
If I am on some other branch and run do-merge 676699a
, what do you want to happen? Note that this particular commit-ID has two labels, origin/master
(a remote branch) and master
(a local branch). I've given neither label as argument, but I've asked to merge that particular commit.
The function as written says that this is not a remote branch. (In particular, git rev-parse --symbolic-full-name
outputs nothing and exits 0, indicating success; the case
then compares the empty string against the two glob patterns and only matches the second.)
If you want something else to happen, you'll need more actions. You can add a case pattern for the empty string, which is the "symbolic full name" you get back for any valid SHA-1 that is not a symbolic name. (This includes things that are not even commits, nor resolvable to commits, too.) You can then do whatever you want for these cases, but you need to figure out what it is you want.
Note that the git-sh-setup
script has a function, peel_commitish
, that can help resolve a revision specifier to a commit. (As with all these cases it winds up using git rev-parse
, this time with the special ^0
suffix, which means the same as ^{commit}
.)
What about octopus merges?
For instance, what does it mean if I am on branch B
and ask to merge (by name) both branches feature1
and origin/feature2
? Am I merging a remote branch or a local one, in terms of whether to use --no-ff --no-commit
by default?