2

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?

Community
  • 1
  • 1
musicmatze
  • 3,603
  • 6
  • 26
  • 43

1 Answers1

1

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.

Caveats

  1. 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}.)

  2. 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?

Community
  • 1
  • 1
torek
  • 330,127
  • 43
  • 437
  • 552