简体   繁体   中英

After merge, how does the commit ID of a merged file (no conflicts) change?

Suppose we have branch A, and branch B.

Branch A works on file a.cpp, and have several commits say commit ID 10000 10001, 10002, 10003 (faked).

Branch B has a.cpp. a.cpp still shows the old commit ID 10000. [Note] Branch B has other commits already. But a.cpp history in Gighub only show one old commit ID 10000.

Now we merge A to B. In B, we have a.cpp. What are its history commit ID series "FOR a.cpp File"? I didn't mean the commit history for B. I mean the history for the file a.cpp (you will see that in Gighub)

Are they same commit IDs?

I assumed they are the same. But from one practical project on Github, I find they are not the same!

The problem is: Someone made modification on some other files in Branch B (not on a.cpp file). Later on I merge B to A, since I work on A, I find that there are conflicts for a.cpp file, although they are the same! (but different commit IDs).

I don't want to resolve the conflicts, which is time-consuming.

[Update 1] Here is some quote from Do the commit ids remain same after a merge?

If your work is rebased (or cherry-picked) into an upstream, and you fetch and then attempt to merge the upstream, git will sometimes, but not always, be able to detect the duplication and clean up automatically. When it cannot auto-detect the duplication, you will almost always get various merge conflicts:

How come? If Git cannot automatically detect no change of some files, it creates a lot of fake merge conflict errors, which is time-consuming to manually solve.

[Update 2] Thanks for answers below. However, in github, I find that different commit IDs for the same commit files, authors and change. See the quote from Do the commit ids remain same after a merge?

I viewed the commit log of the team's branch and realized that although the commit message, author(me) & date were same, the commit id was different in the remote branch.

[Update 3] For Tomato Branch:

1000, 1001, 1002, 1003

For Potato Branch:

1000, 2001, 2002, 2003

Now merge Tomato Branch to Potato Branch:

The common ancestor is 1000, and the merge commit is 2004

Between 1000 and 2004, there are 1001, 1002, 1003, 2001, 2002, 2003.

it seems Git put them between based on chronicle order, AND change the commit name. So it would like

1000

( 3001 (from 1001),

3002 (form 1002),

4001 (from 2001),

4002 (from 2002),

4003 (from 2003),

3003 (from 1003) )

2004

Merge are based on common ancestor 1000, and the two latest commits from the two branches (1003, 2003).

Git also give out 4003, which might mean it also merge:

2003 AND 1002

So actually Git might do many merging operations in order to give out an effective chronicle intermediate commits.

Each commit always contains all files of your repository. If you change any file (and commit that change) you will get a new commit with a new commit id.

  • Without any commit on B:

Before the commit your history looks like this:

10000, 10001, 10002, 10003
  B                    A

You have 4 commits. Branch B points to the first one and branch A to the last one.

After the merge it looks like this:

10000, 10001, 10002, 10003
                      A,B

Git noticed that you did not do any commits on B and therefore simply does a fast-forward. Therefore now both branches point to the same commit.

  • If there was another commit on B:

Before the commit your history looks like this:

10000,    10001,   10002,   10003
   10004                        
     B                        A 

Now commit 10004 was made on branch B. while branch A still points to 10003.

After the merge it looks like this:

10000,    10001,   10002,   10003
   10004                           10005
                             A      B

Now git created a real merge commit (10005) combining 10003 and 10004. If 1004 did not change any file change by A there should be no merge conflict.

To see how things work in git, sometimes I like to use Visualizing Git Concepts with D3 which does a reasonable job of showing how the repository looks with each commit or branch or rebase.

Starting out with:

git branch B
git commit
git commit
git commit

the repo will look like:

在此处输入图片说明

Checking out B ( git checkout B ) brings us to:

在此处输入图片说明

And now to bring the two into sync with a git merge master :

在此处输入图片说明

The history on the side looks like:

在此处输入图片说明

Note the fast-forward merge. Git detected no changes were done on B since the branch so it was able to just move the label.

However, if we don't move to the B branch and instead do a git merge B while on master, we get:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM