500

I have a git branch (the mainline, for example) and I want to merge in another development branch. Or do I?

In order to decide whether I really want to merge this branch in, i'd like to see some sort of preview of what the merge will do. Preferably with the ability to see the list of commits that are being applied.

So far, the best I can come up with is merge --no-ff --no-commit, and then diff HEAD.

Eyal
  • 3,412
  • 1
  • 44
  • 60
Glenjamin
  • 7,150
  • 6
  • 25
  • 26
  • 22
    I'd just `git merge` and `git reset --keep HEAD@{1}` if I don't like the result. – Jan Hudec Apr 28 '11 at 11:49
  • 4
    Note that seeing the list of commits with their diff doesn't necessarily tell the whole story - if the merge is non-trivial, and especially if there are conflicts, the actual result of the merge might be a bit interesting. – Cascabel Apr 28 '11 at 12:44
  • The problem with this is trying to easily see what actual changes have been made. – Glenjamin Apr 28 '11 at 13:41
  • 2
    Your original method does exactly that. The point of my comment is that although looking at individual diffs is all well and good, if you have a complex merge, you may end up with surprising results even if all the merged commits are independently good. – Cascabel Apr 28 '11 at 15:39
  • 2
    @Jan: For some reasons, `git reset --keep HEAD@{1}` returned `fatal: Cannot do a keep reset in the middle of a merge.` Help? – moey Jan 27 '12 at 10:29
  • @Siku-Siku.Com: The command assumes the merge finished and commited the result. I believe the message about conflicts tells you both how to finish and how to abort the merge. – Jan Hudec Jan 27 '12 at 10:40
  • 1
    possible duplicate of [Is there a git-merge --dry-run option?](http://stackoverflow.com/questions/501407/is-there-a-git-merge-dry-run-option) – sschuberth Dec 06 '13 at 10:56
  • 10
    Why isn't there a `--preview` option in git-merge? – Gaui Jun 10 '14 at 17:17
  • I think the most correct answer I've seen for this is here: http://stackoverflow.com/a/6283843/1695680 – ThorSummoner Jul 31 '15 at 16:14

12 Answers12

509
  • git log ..otherbranch
    • list of changes that will be merged into current branch.
  • git diff ...otherbranch
    • diff from common ancestor (merge base) to the head of what will be merged. Note the three dots, which have a special meaning compared to two dots (see below).
  • gitk ...otherbranch
    • graphical representation of the branches since they were merged last time.

Empty string implies HEAD, so that's why just ..otherbranch instead of HEAD..otherbranch.

The two vs. three dots have slightly different meaning for diff than for the commands that list revisions (log, gitk etc.). For log and others two dots (a..b) means everything that is in b but not a and three dots (a...b) means everything that is in only one of a or b. But diff works with two revisions and there the simpler case represented by two dots (a..b) is simple difference from a to b and three dots (a...b) mean difference between common ancestor and b (git diff $(git merge-base a b)..b).

scharette
  • 9,437
  • 8
  • 33
  • 67
Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • 10
    The third dot was the part I was missing, thanks! The log approach works well also, log -p --reverse ..otherbranch seems like a good way to see what would be merged in. – Glenjamin Apr 28 '11 at 12:40
  • 1
    I was missing `git checkout master` before I tried this. I was wondering why it was saying all of my changes were going to be over-written... – yurisich Oct 18 '13 at 22:33
  • 9
    `git show ..otherbranch` will show a list of changes and diff that will be merged into current branch. – Gaui Jun 21 '14 at 17:26
  • Just wanted to add that if you run 'git difftool ...otherbranch' it will actually run mergetool so it is a 3-way diff -- notice it doesn't use the difftool configuration. The left is the ancestor, center is local and right is otherbranch versions. I use Meld as my mergetool (and difftool), but I am sure it would work with others. – noisygecko Apr 05 '16 at 20:24
  • 7
    This is not completely accurate, especially for cherry picks. – void.pointer Aug 08 '16 at 15:30
  • @noisygecko I want to do what you explained in your comment (above), but it doesn't work for me. I've opened a new [question](http://stackoverflow.com/q/41803083/3380131) looking for answers. If you have anything to suggest there, I'd love to hear it! – bitsmack Jan 23 '17 at 17:20
  • @noisygecko, does it? It definitely does not for me. – Jan Hudec Jan 23 '17 at 18:09
  • 4
    @void.pointer, git does not treat cherry-picks specially in normal merge so it does not here either. A merge strategy could be written that would, but as far as I know, it never was. – Jan Hudec Jan 23 '17 at 18:11
  • @JanHudec the problem is if your current branch already cherry-picked (or somehow included) some changes from otherbranch, this will still show them. You only want to see what will actually change. This is especially relevant now with GitHub's "squash and merge" making this a common workflow. – hraban Nov 06 '19 at 12:05
  • @hraban, the middle method will not; `git diff ...branch` will show exactly the diff that `git merge --squash` will apply (sans recursive strategy; I think `diff` isn't able to synthesize the common ancestor in criss-cross in the same way). A `git rebase -i` will also try to exclude any cherry-picked commits, but I don't know how to just show a list of what `git rebase -i` would pick. – Jan Hudec Nov 06 '19 at 12:19
  • @JanHudec I'm not sure if that's true. `git diff ...develop` == `git diff $(git merge-base HEAD develop) develop` == "all changes in develop since the last merge base with HEAD". If you just cherry-picked a change from develop into HEAD, that doesn't change anything about develop, so it will still show up. You can try this locally and observe the difference between that solution, and `git merge-tree $(git merge-base HEAD develop) HEAD develop`. – hraban Nov 07 '19 at 11:29
  • @hraban, A three-way merge is equivalent to applying diff from base to remote on local except for conflict handling. Therefore, `git merge-tree $(git merge-base HEAD develop) HEAD develop` is equivalent to `git diff $(git merge-base HEAD develop) develop | git apply`, which is `git diff ...develop | git apply`. If HEAD already has some of the changes, they will do nothing, but they will still be there. – Jan Hudec Nov 07 '19 at 12:02
  • I can believe that's how it works under the hood. However, if you want to preview a merge, is it practical to have to think at every change: wait was this already cherry-picked? Git apply dropping (or conflicting) those changes is precisely what you'd want to preview. That is if we stick to the original question; if this becomes a question about merging and diffing internals of git, then I am completely with you. – hraban Nov 07 '19 at 12:08
  • @hraban, yeah, true, just doing it and discarding it if it was wrong is easiest and accurate. – Jan Hudec Nov 07 '19 at 12:11
  • 1
    If you want to see it from the other branch's point of view put the 3 dots at the end and it'll show you a preview of the merge of "HEAD" into "otherbranch": `git diff otherbranch...` (useful when you're on a feature branch and you want to know what you'd apply to main). This seems to be what github shows when comparing branches or showing PR diffs. – Tim Abell Jun 21 '22 at 13:34
343

I've found that the solution the works best for me is to just perform the merge and abort it if there are conflicts. This particular syntax feels clean and simple to me. This is Strategy 2 below.

However, if you want to ensure you don't mess up your current branch, or you're just not ready to merge regardless of the existence of conflicts, simply create a new sub-branch off of it and merge that:

Strategy 1: The safe way – merge off a temporary branch:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

That way you can simply throw away the temporary branch if you just want to see what the conflicts are. You don't need to bother "aborting" the merge, and you can go back to your work -- simply checkout 'mybranch' again and you won't have any merged code or merge conflicts in your branch.

This is basically a dry-run.

Strategy 2: When you definitely want to merge, but only if there aren't conflicts

git checkout mybranch
git merge some-other-branch

If git reports conflicts (and ONLY IF THERE ARE conflicts) you can then do:

git merge --abort

If the merge is successful, you cannot abort it (only reset).

If you're not ready to merge, use the safer way above.

[EDIT: 2016-Nov - I swapped strategy 1 for 2, because it seems to be that most people are looking for "the safe way". Strategy 2 is now more of a note that you can simply abort the merge if the merge has conflicts that you're not ready to deal with. Keep in mind if reading comments!]

Community
  • 1
  • 1
Kasapo
  • 5,294
  • 1
  • 19
  • 21
  • 3
    +1 for strategy 2. Temporary branch that shows exactly what will go in when merging. Strategy 1 is what I am trying to avoid for this particular case. – Gordolio Jul 27 '15 at 19:45
  • 3
    I suggest changing the strategies around so the safer one is first (my psych training coming through - most people would assume the best option would be the first one, despite the clear use of the word "safer") but, other than that, excellent job. – paxdiablo Jun 22 '16 at 01:56
  • 11
    You could do a `git merge --no-ff --no-commit` if you do not want to commit the changes directly. This eliminates the "need" for a different branch makes it a tiny bit easier to review the changes, imo. – Gerard van Helden Jul 19 '16 at 16:59
  • and if you decide you don't want to merge at all and in fact would rather write some more code and then commit to your branch so you can deploy JUST your branch on a test server, wouldn't you still have to revert the `git merge --no-ff --no-commit`? I guess you can still do a `git merge --abort` after that if you don't like what you see? Even if the merge doesn't produce conflicts? – Kasapo Jul 19 '16 at 19:44
  • Most people like to copy and paste and not think too much. Therefore, for Strategy 1, perhaps also add how to abort the merge in the temporary local branch `git reset --hard HEAD` and then checkout a different branch `git checkout ` and delete the temporary branch `git delete -b `. – user3613932 Feb 02 '17 at 21:44
  • I think you should add at the end of Strategy 1: if I like the result of the merge in the temporary branch, go back to 'mybranch' and do the actual merge of some-other-branch. (Is that correct?) – ttulinsky May 03 '17 at 21:52
  • @GerardvanHelden you're right, and after that, you'll have two options: 1. `git commit` which will conclude the merge, or 2. `git merge --abort` which will discard the merge. – zaibaq Aug 17 '23 at 06:45
23

Most answers here either require a clean working directory and multiple interactive steps (bad for scripting), or don't work for all cases, e.g. past merges which already bring some of the outstanding changes into your target branch, or cherry-picks doing the same.

To truly see what would change in the master branch if you merged develop into it, right now:

git merge-tree $(git merge-base master develop) master develop

As it's a plumbing command, it does not guess what you mean, you have to be explicit. It also doesn't colorize the output or use your pager, so the full command would be:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

https://git.seveas.net/previewing-a-merge-result.html

(thanks to David Normington for the link)

P.S.:

If you would get merge conflicts, they will show up with the usual conflict markers in the output, e.g.:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

User @dreftymac makes a good point: this makes it unsuitable for scripting, because you can't easily catch that from the status code. The conflict markers can be quite different depending on circumstance (deleted vs modified, etc), which makes it hard to grep, too. Beware.

hraban
  • 1,819
  • 1
  • 17
  • 27
  • 1
    @hraban This looks like the correct answer, however there is still apparently one missing element. This approach requires the user to "eyeball" the output to see if the conflict markers are present. Do you have an approach that simply returns `true` if there are conflicts and `false` if there are no conflicts (e.g., a boolean value that does not require the "eyeball" test or any human intervention). – dreftymac Nov 04 '19 at 04:22
  • 2
    @dreftymac can't find anything to that effect. you could use something like `git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to merge` but it's finnicky; I'm probably forgetting a case. maybe you want to check for the conflict markers, instead? e.g. this probably doesn't catch "theirs deleted, ours changed" style conflicts. (I just checked and that doesn't even show conflict markers, so you need a meticulous regex to be safe here) – hraban Nov 30 '19 at 21:48
  • 1
    Use `less -R` to handle coloured output without modifying your configuration. – Giacomo Alzetta Feb 19 '20 at 11:01
  • This is the only right answer. Now sure why other are upvoted. – DimanNe Nov 04 '21 at 11:19
  • “Most answers here either require a clean working directory” Then do `git worktree add ../test-merge && cd ../test-merge && git merge […]`. The working tree then becomes irrelevant. And you can use the command directly instead of having to think about what `git merge` does in terms of low-level commands. – Guildenstern Apr 16 '23 at 10:14
19

If you're like me, you're looking for equivalent to svn update -n. The following appears to do the trick. Note that make sure to do a git fetch first so that your local repo has the appropriate updates to compare against.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

or if you want a diff from your head to the remote:

$ git fetch origin
$ git diff origin/master

IMO this solution is much easier and less error prone (and therefore much less risky) than the top solution which proposes "merge then abort".

Trevor Boyd Smith
  • 18,164
  • 32
  • 127
  • 177
djschny
  • 689
  • 8
  • 9
  • 1
    should be `$ git checkout target-branch` and then `$ git diff --name-status ...branch-to-be-merged` (three dots are essential so type them as is) – Ilya Serbis Aug 23 '16 at 18:43
  • 1
    One thing this is missing: it doesn't show you which files would have a conflict -- they have the same "M" marker as files that have been modified on the branch but can be merged without any conflicts. – peterflynn Oct 07 '16 at 18:26
  • 1
    Maybe things were different in 2012, but these days aborting a merge seems quite reliable, so I don't think it's fair to characterize this as "much easier and less error prone" right now. – David Z May 22 '20 at 21:22
6

Adding to the existing answers, an alias could be created to show the diff and/or log prior to a merge. Many answers omit the fetch to be done first before "previewing" the merge; this is an alias that combines these two steps into one (emulating something similar to mercurial's hg incoming / outgoing)

So, building on "git log ..otherbranch", you can add the following to ~/.gitconfig :

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

For symmetry, the following alias can be used to show what is committed and would be pushed, prior to pushing:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

And then you can run "git incoming" to show a lot of changes, or "git incoming -p" to show the patch (i.e., the "diff"), "git incoming --pretty=oneline", for a terse summary, etc. You may then (optionally) run "git pull" to actually merge. (Though, since you've already fetched, the merge could be done directly.)

Likewise, "git outgoing" shows what would be pushed if you were to run "git push".

michael
  • 9,161
  • 2
  • 52
  • 49
  • "Many answers omit the fetch" - That is because the question was about merge preview; not pull or push. There is no need to fetch before a merge except in the specific case of pull (although when merging into a branch that exists remotely, it is generally a good idea to pull that branch first, to make sure you have an up-to-date version of it). – Superole Oct 01 '20 at 12:55
  • If you'll re-read your comment closely, you'll see that you conflate "pull" with "merge" and "fetch", which is common, but confusing when the distinction is important (as it is here). https://stackoverflow.com/a/292359/127971 – michael Oct 01 '20 at 22:10
  • =2, "conflate" - cool word! :) I do actually like your answer too, it shows a use case for merge-preview that some may find helpful. Now if you re-read the question, and then my first comment to your answer, you may notice that I fully intended to emphasize that a pull (which in essence is just a fetch followed by a merge) is the only case where you would need to fetch at all before previewing or applying a merge. And the OP asked specifically about the merge part only,which has many use cases apart from updating a local branch with changes on its remote counterpart. – Superole Oct 07 '20 at 08:17
6

If you already fetched the changes, my favourite is:

git log ...@{u}

That needs git 1.7.x I believe though. The @{u} notation is a "shorthand" for the upstream branch so it's a little more versatile than git log ...origin/master.

Note: If you use zsh and the extended glog thing on, you likely have to do something like:

git log ...@\{u\}
4

I tried this thing to review the changes in visual studio code.

Create a temporary branch from dev. Then merge the branch in which you have changed the file with --no-ff --no-commit flag.

git checkout dev 
git checkout -b feature_temp 
git merge feature --no-ff --no-commit

The changed file of your feature branch will be reflecting in the feature_temp branch.

Andronicus
  • 25,419
  • 17
  • 47
  • 88
Piyush Sarin
  • 133
  • 1
  • 5
  • No need to checkout to a temporary branch. You can do it directly on dev. After that, you'll have two options: 1. `git commit` which will conclude the merge, or 2. `git merge --abort` which will discard the merge. – zaibaq Aug 17 '23 at 06:42
3

Short of actually performing the merge in a throw away fashion (see Kasapo's answer), there doesn't seem to be a reliable way of seeing this.

Having said that, here's a method that comes marginally close:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

This gives a fair indication of which commits will make it into the merge. To see diffs, add -p. To see file names, add any of --raw, --stat, --name-only, --name-status.

The problem with the git diff TARGET_BRANCH...SOURCE_BRANCH approach (see Jan Hudec's answer) is, you'll see diffs for changes already in your target branch if your source branch contains cross merges.

antak
  • 19,481
  • 9
  • 72
  • 80
3

Pull Request - I've used most of the already submitted ideas but one that I also often use is ( especially if its from another dev ) doing a Pull Request which gives a handy way to review all of the changes in a merge before it takes place. I know that is GitHub not git but it sure is handy.

G-Man
  • 1,138
  • 16
  • 20
3

git log currentbranch..otherbranch will give you the list of commits that will go into the current branch if you do a merge. The usual arguments to log which give details on the commits will give you more information.

git diff currentbranch otherbranch will give you the diff between the two commits that will become one. This will be a diff that gives you everything that will get merged.

Would these help?

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
  • 2
    Actually, wrong. `git log otherbranch..currentbranch` gives list of commits on *currentbranch*. The `git diff otherbranch currentbranch` gives you diff from the to-be-merged version to current tip, which is about as useless as it can be, because what you want is diff from the merge base to the merge head. – Jan Hudec Apr 28 '11 at 11:52
  • Thanks. I've switched the names of the treeishes. – Noufal Ibrahim Apr 28 '11 at 12:08
1

I do not want to use the git merge command as the precursor to reviewing conflicting files. I don't want to do a merge, I want to identify potential problems before I merge - problems that auto-merge might hide from me. The solution I have been searching for is how to have git spit out a list of files that have been changed in both branches that will be merged together in the future, relative to some common ancestor. Once I have that list, I can use other file comparison tools to scout things out further. I have searched multiple times, and I still haven't found what I want in a native git command.

Here is my workaround, in case it helps anyone else out there:

In this scenario I have a branch called QA that has many changes in it since the last production release. Our last production release is tagged with "15.20.1". I have another development branch called new_stuff that I want to merge into the QA branch. Both QA and new_stuff point to commits that "follow" (as reported by gitk) the 15.20.1 tag.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Here are some discussions that hit on why I'm interested in targeting these specific files:

How can I trust Git merge?

https://softwareengineering.stackexchange.com/questions/199780/how-far-do-you-trust-automerge

Community
  • 1
  • 1
Laura
  • 525
  • 1
  • 4
  • 12
1

Maybe this can help you ? git-diff-tree - Compares the content and mode of blobs found via two tree objects

Chugaister
  • 364
  • 4
  • 12