Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Git merge in depth

Anton Chikin
November 29, 2016

Git merge in depth

How exactly 3-way recursive merge and rebase work.

Anton Chikin

November 29, 2016
Tweet

Other Decks in Technology

Transcript

  1. git merge in depth
    Anton Chikin

    View Slide

  2. test
    branch
    merge
    master
    to branch
    test
    branch
    merge
    branch
    to master
    test
    master

    View Slide

  3. test
    branch
    merge
    master
    to branch
    test
    branch
    merge
    branch
    to master
    test
    master
    WAT

    View Slide

  4. I don’t trust merge!

    View Slide

  5. View Slide

  6. View Slide

  7. 3-way merge

    View Slide

  8. master

    View Slide

  9. master
    branch

    View Slide

  10. master
    branch

    View Slide

  11. master
    branch

    View Slide

  12. master
    branch

    View Slide

  13. master
    branch

    View Slide

  14. master
    branch
    ?

    View Slide

  15. master
    branch
    ?
    var a = “foo”
    def getData(string
    path)
    var data = Map()
    for l in
    visit(path)
    data[l.slot] =
    l.data
    return
    data.JSON()
    var a = “foo”
    def getData(URI
    path)
    var data =
    Array()
    for l in
    visit(path)
    data[l.id] =
    l.data
    return data

    View Slide

  16. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch

    View Slide

  17. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?

    View Slide

  18. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?

    View Slide

  19. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?

    View Slide

  20. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?
    ?

    View Slide

  21. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?
    ?
    Nearest common ancestor
    var a = “foo”
    def getData(string
    path)
    var data = {}
    for l in
    visit(path)
    data[l.slot] =
    l.data
    return data

    View Slide

  22. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    master
    branch

    View Slide

  23. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch

    View Slide

  24. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”

    View Slide

  25. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”

    View Slide

  26. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path) def getData(URI path)
    def getData(string path)

    View Slide

  27. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    def getData(string path)

    View Slide

  28. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}

    View Slide

  29. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    ?????????????

    View Slide

  30. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    ?????????????

    View Slide

  31. def getData(string path)
    <<<<<<< HEAD
    var data = Map()
    ||||||| merged common ancestors
    var data = {}
    =======
    var data = Array()
    >>>>>>> branch

    View Slide

  32. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)

    View Slide

  33. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)

    View Slide

  34. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data

    View Slide

  35. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data

    View Slide

  36. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data
    return data.JSON()

    View Slide

  37. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data
    return data.JSON()

    View Slide

  38. master
    branch
    ?

    View Slide

  39. master
    branch

    View Slide

  40. master
    branch
    merge master into branch

    View Slide

  41. master
    branch
    merge master into branch

    View Slide

  42. branch
    merge branch into master
    master

    View Slide

  43. recursive 3-way merge

    View Slide

  44. master
    Let’s take a look at a more complicated picture

    View Slide

  45. master
    hotfix
    Let’s take a look at a more complicated picture

    View Slide

  46. master
    hotfix
    Let’s take a look at a more complicated picture

    View Slide

  47. master
    feature
    hotfix
    Let’s take a look at a more complicated picture

    View Slide

  48. master
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View Slide

  49. master
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View Slide

  50. master
    M
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View Slide

  51. master
    M
    M
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View Slide

  52. master
    M
    M
    ?
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View Slide

  53. master
    M
    M
    ?
    hotfix
    feature
    Let’s take a look at a more complicated picture
    nearest common ancestor

    View Slide

  54. master
    M
    M
    ?
    hotfix
    feature
    How to deal with two nearest common ancestors?
    nearest common ancestor
    nearest common ancestor

    View Slide

  55. master
    M
    M
    ?
    hotfix
    nearest common ancestor
    Step 1: find nearest common ancestor
    of those ancestors

    View Slide

  56. master
    M
    M
    ?
    hotfix
    Step 2: merge them into “fake” commit
    nearest common ancestor

    View Slide

  57. master
    M
    M
    ?
    hotfix
    Step 3: Merge our commits using that “fake” ancestor
    nearest common ancestor

    View Slide

  58. master
    M
    M
    hotfix
    M
    nearest common ancestor
    This process can be recursive

    View Slide

  59. master
    M
    M
    hotfix
    feature
    M

    View Slide

  60. And what about rebase?

    View Slide

  61. master
    branch
    master
    A B C

    View Slide

  62. master
    branch
    master
    A B C
    nearest common ancestor
    Again, find NCO

    View Slide

  63. master
    branch
    master
    diff B diff C
    diff A
    A B C
    Create diffs between each commits starting from NCO

    View Slide

  64. master
    branch
    master
    A B C
    diff B diff C
    diff A
    Move branch head to master

    View Slide

  65. master
    branch
    master
    A B C
    A’
    diff B diff C
    Apply each diff on top of latest master commit

    View Slide

  66. master
    branch
    master
    A B C
    A’ B’
    diff C
    Apply each diff on top of latest master commit

    View Slide

  67. master
    branch
    master
    A B C
    A’ B’ C’
    Apply each diff on top of latest master commit

    View Slide

  68. @1,1
    - A
    + B
    What does it mean to “apply diff”?
    Diff format is quite simple:
    In the first line

    View Slide

  69. @1,1
    - A
    + B
    Diff format is quite simple:
    In the first line
    replace “A”
    What does it mean to “apply diff”?

    View Slide

  70. @1,1
    - A
    + B
    Diff format is quite simple:
    In the first line
    replace “A”
    with “B”
    What does it mean to “apply diff”?

    View Slide

  71. A
    B
    C
    @1,1
    - A
    + B
    B
    B
    C
    What does it mean to “apply diff”?

    View Slide

  72. D
    B
    C
    @1,1
    - A
    + B
    ????????
    B
    C
    What if first line in file is not “A” but “D”?
    Same as in merge - conflict!
    What does it mean to “apply diff”?

    View Slide

  73. D
    B
    C
    @1,1
    - A
    + B
    ????????
    B
    C
    What if first line in file is not “A” but “D”?
    Same as in merge - conflict!
    What does it mean to “apply diff”?

    View Slide

  74. master
    branch
    branch
    master
    A’ B’ C’
    A B C
    M
    Merge and rebase give you different branch structure
    but the same result

    View Slide

  75. Merge commits “train station”

    View Slide

  76. Merge commits “subway”

    View Slide

  77. Finally
    - don’t be afraid of recursive merge
    - merge a ->b == merge b ->a
    - merge == rebase
    - prefer merge over rebase
    - merge will never never let you down

    View Slide

  78. •http://think-like-a-git.net/
    •http://git-school.github.io/visualizing-git/
    Resources

    View Slide

  79. Questions?

    View Slide

  80. git merge in depth
    Anton Chikin

    View Slide