Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to get a hash of merge commit before merge?

Tags:

git

Let's say I have 2 branches - master and feature. Also I have a pull request with 2 commits from feature to master. If I merge it I ll have a merge commit. Is this commit already configured somehow before merge? Can I look at it somehow? I know that I can get hash of refs/pull-requests/1/from and refs/pull-requests/1/merge branches, but can I get something like "merge" commit?

like image 957
MarkBeras Avatar asked Jun 17 '19 15:06

MarkBeras


People also ask

Does merge change commit hash?

Merges make new commits (assuming you do them in such a way as to avoid a "fast forward" operation, anyway). This new commit M has a different ID from every other commit, but commit D is completely unchanged and therefore still has its same ID ( 740c281... ).

How can I see the last commit before merge?

You may try git log -1 , it would give details of last commit of the selected branch. Similarly, git log -2 would give details of last 2 commits. Also try using gitk to visualise the structure, and to check any command scripts, just in case they don't get the right merge-base (fork-point).

Should I commit before merge?

Because Git is distributed , you can maintain multiple copies of a repository. This means you can have one version of a repository on one computer, another version on another computer, and one central version to which every copy refers.

Is it possible for a fast forward merge to have conflicts?

Note that merge conflicts will only occur in the event of a 3-way merge. It's not possible to have conflicting changes in a fast-forward merge.


1 Answers

First, let's answer the question you didn't know to ask

... I know that I can get hash of refs/pull-requests/1/from and refs/pull-requests/1/merge branches, but can I get something like "merge" commit?

These are not Git features, these are Bitbucket features. (It's possible some other web service uses the same technique, but I will assume Bitbucket here.) See https://community.atlassian.com/t5/Bitbucket-questions/Difference-of-refs-pull-requests-lt-ID-gt-merge-and-refs-pull/qaq-p/772142 (and note the caveats in that question's answer).

These two are technically not branches, except that this depends on how we define the word branch. See What exactly do we mean by "branch"? But they are commit hash IDs. The hash ID given by refs/pull-requests/1/from always exists and is the tip commit of the series of commits that whoever made PR#1 had when they made the Pull Request. The name refs/pull-requests/1/merge may not exist, but if it does exist, it is the hash ID of a merge commit that Bitbucket already made. This is the result of the test merge that Bitbucket tried, to see whether or not the pull request can be merged as-is.

If the merge commit already exists, you can retrieve it into your own Git repository. Note that if it does exist, that means Bitbucket's Git was able to resolve the merge without human assistance. You can therefore have your Git do the same, if that is easier or more convenient than obtaining their merge. While you'll get a different merge commit, it will have the same associated tree: see below.

Why the original question is a little silly

The hash ID of a commit is computed by hashing the contents of the commit.

Here are the contents of a sample commit (but with @ changed to to maybe possibly decrease someone's spam-load):

tree a830f927ccaf7164b03602729cc7078c79d5bbf2
parent fab4a8a39666793d407371f519e8b6d25d33fa84
author Junio C Hamano <gitster pobox.com> 1558252002 +0900
committer Junio C Hamano <gitster pobox.com> 1558252002 +0900

Git 2.22-rc1

Signed-off-by: Junio C Hamano <gitster pobox.com>

Note that the tree of a merge (the hash ID after the word tree here) is unknown until after doing the merge, but you could do the merge to find the tree and then you will know the tree.

The above is a non-merge commit; here's a merge commit:

tree ea8851107dda1a726b3eec91d347996ead1ab683
parent 8c59ba9a764f1ae1f8d176ea17c636183cfd7267
parent f3a3a021c716b46ed35e6b7171bbff4d8042da68
author Junio C Hamano <gitster pobox.com> 1558251935 +0900
committer Junio C Hamano <gitster pobox.com> 1558251935 +0900

Merge branch 'js/difftool-no-index'

The "--dir-diff" mode of "git difftool" is not useful in "--no-index"
mode; they are now explicitly marked as mutually incompatible.

* js/difftool-no-index:
  difftool --no-index: error out on --dir-diff (and don't crash)

The key difference is that the merge has two parents. The parents of the merge are obvious: the first one is the current commit before you do the merge, and the other is hash ID of the commit you intend to merge.

After the tree and parent lines, though, come the author and committer lines. These not only contain a known quantity—the name and email address—but also an unpredictable one: the exact second at which the merge is done (1558252002 for instance).

The rest of the merge commit contents are the commit message, which presumably you know.

So, in order to predict the merge, you need to:

  • Perform the merge, to find the tree
  • Predict the time at which you'll do the merge later

Once you know these two bits of data, you can fill out the header contents and compute the hash ID of the merge.

Of course, that first step—perform the merge—now suffices: you have the merge; so just use it. This is also why Bitbucket perform a test merge—as do GitHub, though their names are refs/pull/number/head and refs/pull/number/merge.

like image 55
torek Avatar answered Oct 17 '22 07:10

torek