Lecture 14: Version control and git part 2

Remember: Commits and Branches

Changing to different commits

Use git checkout <branch> or git checkout <commit hash>.

Merging and rebasing

Setup:

Solutions:

Fast-forward merge

Setup: We have two commits, branch1 and branch2, and branch1 is an ancestor of branch2.

We would like to update so that branch1 points to the same commit as branch2.

Solution: fast-forward merge

git checkout branch1
git merge branch2

What happens?

For example

After running

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

Basic merge

Setup: We have a diverged work history with branch1 and branch2.

We want to integrate the changes represented by both branches.

We can merge the two branches:

git checkout branch1
git merge branch2

What happens?

Starting out:

How we want the merge to look:

After running

git checkout master
git merge iss53

Merge conflicts

Sometimes merging doesn’t work automatically, usually because you made different changes to the same file on different branches.

If this happens, you’ll get a message telling you that the merge can’t be performed automatically:

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

If you run git status, you get instructions about what to do:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

In this case, the file index.html will contain a section that looks like this:

<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

Resolving the conflict:

After fixing merge conflicts and running git add index.html:

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   index.html

Rebase

Setup: We have a diverged work history with branch1 and branch2.

We want to integrate the changes represented by both branches.

One solution is rebasing branch2 onto branch1:

git checkout branch2
git rebase branch1

What happens?

Same result as what we would get from a merge commit, but the history is different.

Starting out:

After running:

git checkout experiment
git rebase master

After running:

git checkout master
git merge experiment

Remotes

Showing the remotes

To see the remote servers corresponding to your project that you have set up, use git remote, or git remote -v.

For example:

$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin
$ git remote -v
origin  https://github.com/schacon/ticgit (fetch)
origin  https://github.com/schacon/ticgit (push)

If you had multiple remotes, you might get something like this:

$ cd grit
$ git remote -v
bakkdoor  https://github.com/bakkdoor/grit (fetch)
bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
cho45     https://github.com/cho45/grit (push)
defunkt   https://github.com/defunkt/grit (fetch)
defunkt   https://github.com/defunkt/grit (push)
koke      git://github.com/koke/grit.git (fetch)
koke      git://github.com/koke/grit.git (push)
origin    git@github.com:mojombo/grit.git (fetch)
origin    git@github.com:mojombo/grit.git (push)

Adding remote repositories

With git clone:

With git remote add:

Fetching from remote repositories

To get new commits that have been added to a remote repository, run git fetch <remote>

What happens?

Remote-tracking branches

Problem: how do we refer to branches in the remote? There’s nothing preventing the remote from having branches with the same name as our local branches but that point to different commits.

Solution: remote-tracking branches:

Inspecting remotes

If you want more information about a remote, you can use git remote show <remote-name>.

For example:

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/schacon/ticgit
  Push  URL: https://github.com/schacon/ticgit
  HEAD branch: master
  Remote branches:
    master                               tracked
    dev-branch                           tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

A more complicated example:

$ git remote show origin
* remote origin
  URL: https://github.com/my-org/complex-project
  Fetch URL: https://github.com/my-org/complex-project
  Push  URL: https://github.com/my-org/complex-project
  HEAD branch: master
  Remote branches:
    master                           tracked
    dev-branch                       tracked
    markdown-strip                   tracked
    issue-43                         new (next fetch will store in remotes/origin)
    issue-45                         new (next fetch will store in remotes/origin)
    refs/remotes/origin/issue-11     stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    dev-branch merges with remote dev-branch
    master     merges with remote master
  Local refs configured for 'git push':
    dev-branch                     pushes to dev-branch                     (up to date)
    markdown-strip                 pushes to markdown-strip                 (up to date)
    master                         pushes to master                         (up to date)

Tracking branches

Tracking branches: not the same as remote-tracking branches

When/how are they created?

What are they for?

Pushing to remote repositories

Method 1: Explicitly naming the local and remote branches

Method 2: If you are on a tracking branch

Note:

Pulling

Setup: You are on a tracking branch, and you want to get any new commits from the upstream branch on the remote.

You can use git pull, which is usually equivalent to git fetch plus git merge <tracking-branch> <remote>/<upstream>, where <tracking-branch> is the branch that you are currently on, and <remote>/<upstream> is the upstream branch that your <tracking-branch> tracks.

Back to the example

$ git remote show origin
* remote origin
  URL: https://github.com/my-org/complex-project
  Fetch URL: https://github.com/my-org/complex-project
  Push  URL: https://github.com/my-org/complex-project
  HEAD branch: master
  Remote branches:
    master                           tracked
    dev-branch                       tracked
    markdown-strip                   tracked
    issue-43                         new (next fetch will store in remotes/origin)
    issue-45                         new (next fetch will store in remotes/origin)
    refs/remotes/origin/issue-11     stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    dev-branch merges with remote dev-branch
    master     merges with remote master
  Local refs configured for 'git push':
    dev-branch                     pushes to dev-branch                     (up to date)
    markdown-strip                 pushes to markdown-strip                 (up to date)
    master                         pushes to master                         (up to date)

Summing up