0

Consider there is a branch A. I created 2 branches A1,A2 from branch A. Again created a branch A21 from branch A2.. I changed line no 2 in X file and did commit and push to A21. Now I merged these changed to A2.. Now i changed the checkout to A2. when I do merge origin/A there is no conflict.. How? I learnt that during merge if there is difference in same line or file is deleted conflict occurs. But in above mentioned scenario changes made in A2 remains same after merge and conflict also doesn't occur.. can anyone explain why.

  • I'm not an expert here, but Git has a merge algorithm which may be able to resolve things automatically, if it decides that it knows what to do. There is no guarantee that every merge would pause with conflicts. – Tim Biegeleisen Aug 02 '18 at 01:57
  • @TimBiegeleisen over 183k rep and golden `git` tag, but no expert, huh ? :'-) Good grief, if so, what am I? Oh. – Romain Valeri Aug 02 '18 at 03:59
  • @RomainVALERI Read Torek's answer below and you will see I rate myself as such :-) – Tim Biegeleisen Aug 02 '18 at 04:03
  • 1
    @TimBiegeleisen I've seen his posts repeatedly and it's beautiful :'-) Also, I'm sorry having started this off-topic chat here while I know it's not the place. I'll erase my comments later today... god I love git. – Romain Valeri Aug 02 '18 at 04:09

3 Answers3

2

First: Do not look at the branch names. Look at the commits and the commit graph. You will use the names only to find the commits themselves, after that you use the graph. Use a graph viewer, or run git log --graph (perhaps with --all --decorate --oneline as well). You will see images or text with line connecting commits to their parent commits, forming a tree or graph structure:

*    a123456  last commit on A1
*    a123457  another commit on A1
| *  a2fedcb  last commit on A2
|/
*  a0dead0  latest shared commit reachable from both A1 and A2
.
.
.

for instance, or see the image below from this answer to Viewing full version tree in git.

Once you have the graph, it should become relatively clear what the term merge base means. The merge base of two particular commits is the commit that the two branches share. In the above output, that would be commit a0dead0.

If we re-draw the graph horizontally, it may be clearer how the two branches diverge:

          o--...--X   <-- you-are-on-this-branch (HEAD)
         /
...--o--*
         \
          o--...--Y   <-- you-ask-to-merge-this

Here, commit * is the merge base, commit X—the commit you have checked out right now—is HEAD, and commit Y is the other commit you are asking to merge.

Now, the way git merge works is, in essence, to start from the merge base itself. Git extracts the merge base commit, and looks at both of your branch tip commits X and Y. Git compares the merge base to commit X to see what you did:

git diff --find-renames <hash-of-*> <hash-of-X>

Then, Git compares the merge base to commit Y to see what they did:

git diff --find-renames <hash-of-*> <hash-of-Y>

Git now simply combines the two sets of changes, applies them all to whatever is in the merge base, and—if all goes well—makes the new merge commit, which moves your current branch as well:

          o--...--X
         /         \
...--o--*           M   <-- you-are-on-this-branch (HEAD)
         \         /
          o--...--Y   <-- you-ask-to-merge-this

The two parents of the merge are the two commits that were merged, i.e., X and Y, in that order.

The merge succeeds if Git can combine the changes.

The merge fails if Git cannot combine the changes.

If you and they made the same change to the same line(s) of the same files, Git can combine those two changes very easily, by taking one copy of the change. So that is what Git does.

You get a conflict if you made different changes to the same lines from the merge base (commit *).

Git optimizes this whole process quite a bit, and often does not have to physically extract commit * at all, but in principle, this is how the merge works.


(Sample gitk image)

image from stackoverflow.com/a/18287861/1256452

torek
  • 448,244
  • 59
  • 642
  • 775
  • Okay, I did two no identical changes on the same file on the same line in two different branches and then merged them, git did not raised any conflict, it just went with Fast-forward. – Waqas Younis Jul 06 '22 at 07:45
  • @WaqasYounis: *fast-forward* is a property of the *graph*. Merge conflicts, or lack thereof, is something that can happen if and only if the merge *cannot* be performed as a fast-forward. So if you ever see "fast-forward" you can be sure that there were no conflicts, and that the merge was trivial and Git didn't actually do any merging. – torek Jul 06 '22 at 07:52
  • that's the problem. If the same file is edited on two different branches and committed then there must be a conflict when merged, – Waqas Younis Jul 06 '22 at 08:07
  • @WaqasYounis: you cannot get that from Git. Use some other approach to whatever your ultimate goal is. For instance, if you're trying to generate a unique version number, use `git describe` to turn the commit hash ID into a usable name. – torek Jul 06 '22 at 14:33
0

Addiotionally to what @torek said, git will deal with the merge without a conflict when changes are identical even if the changes were made independently.

Here I make an identical change in the same file in branch1 and branch2 independently and then merge branch2 onto branch1

/mnt/c/git/ConsoleApp1 (branch1)>git commit -a -m "Adding Foo in branch1"
[branch1 c03dcc2] Adding Foo in branch1
 1 file changed, 4 insertions(+)
/mnt/c/git/ConsoleApp1 (branch1)>git checkout develop
error: pathspec 'develop' did not match any file(s) known to git.
/mnt/c/git/ConsoleApp1 (branch1)>git checkout master
Switched to branch 'master'
/mnt/c/git/ConsoleApp1 (master)>git checkout -b branch2
Switched to a new branch 'branch2'
/mnt/c/git/ConsoleApp1 (branch2)>git commit -a -m "Adding Foo in branch2"
[branch2 d433128] Adding Foo in branch2
 1 file changed, 4 insertions(+)
/mnt/c/git/ConsoleApp1 (branch2)>git merge branch1
Merge made by the 'recursive' strategy.

Result: no conflict.

tymtam
  • 31,798
  • 8
  • 86
  • 126
0

In your description, you only talk about a single change:

I changed line no 2 in X file and did commit and push to A21.

You never say something like "... and on branch A I changed line no 2 in X file to something else and commited it."

If that is the true situation (i.e., there was only a single change in the game), then there is no possibility of a conflict to occur.

j6t
  • 9,150
  • 1
  • 15
  • 35