ChatGPT解决这个技术问题 Extra ChatGPT

How can I preview a merge in git?

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.

I'd just git merge and git reset --keep HEAD@{1} if I don't like the result.
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.
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.
@Jan: For some reasons, git reset --keep HEAD@{1} returned fatal: Cannot do a keep reset in the middle of a merge. Help?
Why isn't there a --preview option in git-merge?

s
scharette

git log ..otherbranch list of changes that will be merged into current branch.

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

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.

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


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.
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...
git show ..otherbranch will show a list of changes and diff that will be merged into current branch.
This is not completely accurate, especially for cherry picks.
@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.
C
Community

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!]


+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.
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.
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.
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?
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 <different branch name> and delete the temporary branch git delete -b <name of temporary branch>.
h
hraban

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 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 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)
Use less -R to handle coloured output without modifying your configuration.
This is the only right answer. Now sure why other are upvoted.
T
Trevor Boyd Smith

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".


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)
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.
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.
P
Pablo Olmos de Aguilera C.

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\}

m
michael

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".


"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).
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). stackoverflow.com/a/292359/127971
=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.
N
Noufal Ibrahim

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?


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.
Thanks. I've switched the names of the treeishes.
a
antak

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.


G
G-Man

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.


C
Chugaister

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


C
Community

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


A
Andronicus

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.