Thursday, July 5, 2012

Using Git and Github for small project collaboration



Way too many words have been written about git.


So here are some really terse notes to create a git project and share it at github.com.


Many references are listed at bottom.

Step 1 of 8. Github Account Setup

Prereqs

    Select
        github username:  eg sag
        github password:  xxxx
        email to be used with github account:  sag@sag.com

    Generate SSH public & private keys on your laptop

        ssh-keygen -t rsa -C "sag@sag.com"
        Specify filename when prompted: sag.id_rsa

    Specify credentials for github in SSH config file  ~/.ssh/config

        Host github.com
            User sag
            IdentityFile ~/.ssh/sag.id_rsa

Create free Github account

    http://github.com-> Plans, Pricing, and Signup-> Create a free account->
        username    sag
        email       sag@sag.com
        password    xxxx
        password    xxxx
    create

Add SSH public key to github account

    cat ~/.ssh/sag.id_rsa.pub
    copy to clipboard
 
    http://github.com-> sign in-> Account Settings-> SSH Keys-> Add SSH Key
    paste into 'key' textbox
    enter github password xxxx

    Confirm ssh auth to github
        ssh git@github.com
            PTY allocation request failed on channel 0
            Hi sag! You've successfully authenticated, but GitHub does not provide shell access.
            Connection to github.com closed.



Step 2 of 8. Create Local Project on Laptop

Prereqs

    Install git on your laptop

    Optional: Configure git globally
        git config –global user.name sag
        git config –global user.email sag@sag.com
        Verify:
            cat ~/.gitconfig

Create directory for new project on laptop

    mkdir testproj
    cd testproj/

Create local git repository

    git init
        Inspect repository in directory testproj/.git

    Optional: Configure git locally
        git config user.name sag
        git config user.email sag@sag.com
        Verify:
            cat .git/config
     
Create some files

    echo "file1" > file1.txt
    echo "file2" > file2.txt
    echo "file3" > file3.txt

Track the files under git

    git add file1.txt
    git add file2.txt
    git add file3.txt

Query status

    git status
    # On branch master
    #
    # Initial commit
    #
    # Changes to be committed:
    #   (use "git rm --cached <file>..." to unstage)
    #
    # new file:   file1.txt
    # new file:   file2.txt
    # new file:   file3.txt
    #

Commit the changes to the local repository, master branch

    git commit -m "First commit."
        [master (root-commit) 15a975d] First commit.
         3 files changed, 3 insertions(+), 0 deletions(-)
         create mode 100644 file1.txt
         create mode 100644 file2.txt
         create mode 100644 file3.txt

Query status

    git status
    # On branch master
    nothing to commit (working directory clean)

Change one file, create another

    echo "blob" >> file1.txt
    echo "file4" > file4.txt
    git add file4.txt

Query status

    git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    # new file:   file4.txt
    #
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    # modified:   file1.txt
    #

Commit the changes to the local repository, master branch

    git commit -m "Commit 2."
        [master aa8a791] Commit 2.
         1 files changed, 1 insertions(+), 0 deletions(-)
         create mode 100644 file4.txt


Step 3 of 8. Local Branch - Simple Changes

Note: default branch is named 'master'

Ensure no current changes

    git status
        # On branch master

Query current branch

    git branch
        * master

Create new branch, equivalent to master branch

    git branch br1

Change local working directory to new branch

    git checkout br1
        Switched to branch 'br1'

    Confirm
        git branch
            * br1
              master

Change some code

    rm file4.txt
    git rm file4.txt

    echo "blob" >> file3.txt
    git add file3.txt

    echo "file0" > file0.txt
    git add file0.txt

Query status

    git status
        # On branch br1
        # Changes to be committed:
        #   (use "git reset HEAD <file>..." to unstage)
        #
        # new file:   file0.txt
        # modified:   file3.txt
        # deleted:    file4.txt

Commit to branch br1

    git commit -m "First commit to br1."

Query differences between current branch br1 and master

    git diff master
        diff --git a/file0.txt b/file0.txt
        new file mode 100644
        index 0000000..dc3ab4a
        --- /dev/null
        +++ b/file0.txt
        @@ -0,0 +1 @@
        +file0
        diff --git a/file3.txt b/file3.txt
        index 7c8ac2f..128c6e3 100644
        --- a/file3.txt
        +++ b/file3.txt
        @@ -1 +1,2 @@
         file3
        +blob
        diff --git a/file4.txt b/file4.txt
        deleted file mode 100644
        index bfd6a65..0000000
        --- a/file4.txt
        +++ /dev/null
        @@ -1 +0,0 @@
        -file4

Confirm

    ls
        file0.txt  file1.txt  file2.txt  file3.txt

Go to branch master

    git checkout master
        Switched to branch 'master'

    Confirm
        ls
            file1.txt  file2.txt  file3.txt  file4.txt

Merge from branch br1 to branch master

    git merge br1  
        Updating 8147115..0d36824
        Fast-forward
         file0.txt |    1 +
         file3.txt |    1 +
         file4.txt |    1 -
         3 files changed, 2 insertions(+), 1 deletions(-)
         create mode 100644 file0.txt
         delete mode 100644 file4.txt

    Confirm
        ls
            file0.txt  file1.txt  file2.txt  file3.txt
        git status
            # On branch master
            nothing to commit (working directory clean)

Delete br1

    git branch -d br1
        Deleted branch br1 (was 0d36824).

    Confirm
        git branch
            * master

Step 4 of 8.  Local Branch - Diff Collisions

Create new branch equivalent to master branch

    git branch br2

Confirm still in branch master
    git branch
        br2
        * master

Change file in branch master

    echo "change in branch master" >> file0.txt
    git add file0.txt
    git commit -m "master changed file0"
        [master c3ac14c] master changed file0
         1 files changed, 1 insertions(+), 0 deletions(-)
    Confirm
        git status
            # On branch master
            nothing to commit (working directory clean)
        cat file0.txt
            file0
            change in branch master  

Change to branch br2

    git checkout br2
        Switched to branch 'br2'
    Confirm
        cat file0.txt
            file0

Change same file in br2 (intentional collision)

    echo "change in branch br2" >> file0.txt
    git add file0.txt
    git commit -m "br2 changed file0"
        [br2 6717435] br2 changed file0
         1 files changed, 1 insertions(+), 0 deletions(-)
    Confirm
        git status
            # On branch br2
            nothing to commit (working directory clean)
        cat file0.txt
            file0
            change in branch br2

Query differences between current branch br1 and master

    git diff master
        diff --git a/file0.txt b/file0.txt
        index c661097..3b65600 100644
        --- a/file0.txt
        +++ b/file0.txt
        @@ -1,2 +1,2 @@
         file0
        -change in branch master
        +change in branch br2

Go to branch master

    git checkout master
        Switched to branch 'master'

    Confirm
        ls
            file1.txt  file2.txt  file3.txt  file4.txt

Merge from branch br1 to branch master

    git merge br1  

    Confirm
        cat file0.txt
            file0
            change in branch master

Fail to do a simple merge

    git merge br2
        Auto-merging file0.txt
        CONFLICT (content): Merge conflict in file0.txt
        Automatic merge failed; fix conflicts and then commit the result.

    Confirm
        git status
            # On branch master
            # Unmerged paths:
            #   (use "git add/rm <file>..." as appropriate to mark resolution)
            #
            # both modified:      file0.txt
            #
            no changes added to commit (use "git add" and/or "git commit -a")

Inspect changes written by git to local repository, master branch

    cat file0.txt
        file0
        <<<<<<< HEAD
        change in branch master
        =======
        change in branch br2
        >>>>>>> br2

Resolve differences

    Manually edit file0.txt

    git commit -m "resolved changes from br2"
        [master db14e1a] resolved changes from br2

    Confirm
        git status
            # On branch master
            nothing to commit (working directory clean)
        cat file0.txt
            file0
            change in branch master and in branch br2


Step 5 of 8.  Create Remote Repository at Github

Prereq

    Confirm you still have SSH auth to access Github
        ssh git@github.com
            PTY allocation request failed on channel 0
            Hi sag! You've successfully authenticated, but GitHub does not provide shell access.
            Connection to github.com closed.

Create a repository at github

    http://github.com-> sign in-> Create a new repo (tiny icon in upper-right)
        name:  testproj
        select:  public
        uncheck:  create README
    click button 'Create'

Configure the local project to access the new github repository
(Note I specify the name 'github' for the remote, rather than default 'origin'.)

    git remote add github git@github.com:sag/testproj.git

    Confirm
        git remote -v
            github git@github.com:sag/testproj.git (fetch)
            github git@github.com:sag/testproj.git ( )
        cat .git/config
            [remote "github"]
            url = git@github.com:sag/testproj.git
            fetch = +refs/heads/*:refs/remotes/github/*

Upload the local project to the new github repository

    git push -u github master
        Counting objects: 27, done.
        Delta compression using up to 2 threads.
        Compressing objects: 100% (16/16), done.
        Writing objects: 100% (27/27), 2.31 KiB, done.
        Total 27 (delta 2), reused 0 (delta 0)
        To git@github.com:sag/testproj.git
         * [new branch]      master -> master
        Branch master set up to track remote branch master from github.

    Confirm
        http://github.com-> sign in-> Repositories-> testproj-> tab Files-> see list of files
            testproj /
            name        age          message
            file0.txt 2 hours ago resolved changes from br2
            file1.txt 3 hours ago Commit 4.
            file2.txt 5 hours ago First commit.
            file3.txt 3 hours ago First commit to br1.
        Click on a file to view its contents

Develop and upload new code from master

    git branch br3
    git checkout br3
    echo "file5 created in br3" > file5.txt
    git add file5.txt
    git commit

    git checkout master
    git diff br3
        diff --git a/file5.txt b/file5.txt
        deleted file mode 100644
        index c994a36..0000000
        --- a/file5.txt
        +++ /dev/null
        @@ -1 +0,0 @@
        -file5 created in br3
    git merge br3
        Updating db14e1a..1ec1d13
        Fast-forward
        file5.txt |    1 +
        1 files changed, 1 insertions(+), 0 deletions(-)
        create mode 100644 file5.txt

    Confirm 1 commit ahead of github/master:
        git status
            # On branch master
            # Your branch is ahead of 'github/master' by 1 commit.
            #
            nothing to commit (working directory clean)

    git push github master
        Counting objects: 4, done.
        Delta compression using up to 2 threads.
        Compressing objects: 100% (2/2), done.
        Writing objects: 100% (3/3), 292 bytes, done.
        Total 3 (delta 1), reused 0 (delta 0)
        To git@github.com:sag/testproj.git
        db14e1a..1ec1d13  master -> master

    Confirm
        git status
            # On branch master
            nothing to commit (working directory clean)
        http://github.com-> sign in-> Repositories-> testproj-> tab Files-> refresh the list of files
            See file5.txt

Develop and upload new code from an arbitrary branch

    git branch br4
    git checkout br4
    echo "file6 created in br4" > file6.txt
    git add file6.txt
    git commit

    git push github br4
        Counting objects: 4, done.
        Delta compression using up to 2 threads.
        Compressing objects: 100% (2/2), done.
        Writing objects: 100% (3/3), 292 bytes, done.
        Total 3 (delta 1), reused 0 (delta 0)
        To git@github.com:sag/testproj.git
         * [new branch]      br4 -> br4

    Confirm
        http://github.com-> sign in-> Repositories-> testproj-> tab Branches-> see the list of files
            See file6.txt


Step 6 of 8. Simple Collaboration with an Untrusted Partner

aka Fork & Pull.  Merge at github website

Prereqs

    Untrusted partner:
        has github account
            username seep
        has SSH access to git@github.com
        discovers your project 'testproj'
        decides to contribute

Fork repository at Github

    Untrusted partner:
        http://github.com-> sign in-> search and find username sag & repository testproj
        click 'Fork' (tiny button in upper-right)
        wait
        New screen appears under untrusted partner account with repository 'testproj'

        Confirm
            Browse files at github, confirm content

Clone repository from Github to partner laptop
(Note I specify the name 'github', rather than default 'origin'.)

    Untrusted partner:
        git clone -o github git@github.com:seep/testproj.git  testproj
            Cloning into 'testproj'...
            remote: Counting objects: 33, done.
            remote: Compressing objects: 100% (16/16), done.
            remote: Total 33 (delta 4), reused 33 (delta 4)
            Receiving objects: 100% (33/33), done.
            Resolving deltas: 100% (4/4), done.

        Confirm
            cd testproj
            ls
                file0.txt  file1.txt  file2.txt  file3.txt  file5.txt

        Optional: Configure git locally
            git config user.name seep
            git config user.email seep@seep.com
            Verify:
                cat .git/config

Contribute

    Untrusted partner:      
        git branch branch-a
        git checkout branch-a
            Switched to branch 'branch-a'
        echo file1a > file1a.txt
        git add file1a.txt
        git commit -m "Added file1a.txt under branch-a"
            [branch-a 5ce79c4] Added file1a.txt under branch-a
            1 file changed, 1 insertion(+)
            create mode 100644 file1a.txt

Upload contribution to github

    Untrusted partner:
        git push github branch-a
            Counting objects: 4, done.
            Delta compression using up to 2 threads.
            Compressing objects: 100% (2/2), done.
            Writing objects: 100% (3/3), 274 bytes, done.
            Total 3 (delta 1), reused 0 (delta 0)
            To git@github.com:seep/testproj.git
             * [new branch]      branch-a -> branch-a

        Confirm
            http://github.com-> sign in-> tab Branches-> branch-a-> see the list of files
                See file1a.txt

Initiate pull request from laptop to github

    Untrusted partner:
        http://github.com-> sign in-> tab Branches-> branch-a
        Click 'Pull Request'
        Type message to owner in textbox
            Please be so kind as to accept my humble contribution
        Click 'Send pull request'
        See request in list of pull requests, state 'open'

    You:
        Receive notification email from contributor
            Sender: untrusted partner seep-ADE9848T7DKROEFORE9K6K43F @ reply.github.com
            Subject:  [testproj] Added file1a under branch-a (#1)
        http://github.com-> sign in-> Pull Requests-> Public
        See one pull request from contributor with message
        Click the pull request
        Review changes:
            click tab discussion, exchange Q&A
            click tab commits, review
            click tab diffs, review
        Accept contribution into branch master at github
            click button Merge Pull Request-> Confirm
        Accept contribution into local master from github
            git pull
                Updating 1ec1d13..81e9140
                Fast-forward
                 file1a.txt |    1 +
                 1 files changed, 1 insertions(+), 0 deletions(-)
                 create mode 100644 file1a.txt      

Delete forked repository

    Untrusted partner:
        Optional:
            http://github.com-> sign in-> forked repo-> Admin-> Delete this repository-> Confirm
            rm -rf testproj/


Step 7 of 8. Slightly More Complex Collaboration with an Untrusted Partner

aka Fork & Pull.  Merge from your laptop.

Same as previous step.  Untrusted partner forks repo, creates branch, checkout branch.

Modify an existing file

    Untrusted partner
        git branch branch-b
        git checkout branch-b
            Switched to branch 'branch-b'
        echo "file1a modified by branch-b" >> file1a.txt
        cat file1a.txt
            file1a
            file1a modified by branch-b
        git add file1a.txt
        git commit -m "file1a modified by branch-b"

Upload branch to github

    Untrusted partner
        git push github branch-b
            Counting objects: 5, done.
            Delta compression using up to 2 threads.
            Compressing objects: 100% (2/2), done.
            Writing objects: 100% (3/3), 294 bytes, done.
            Total 3 (delta 1), reused 0 (delta 0)
            To git@github.com:seep/testproj.git
            * [new branch]      branch-b -> branch-b
        Confirm http://github.com-> sign in-> click forked repository testproj-> Branches
            See branch-b and br4
        Click branch-b-> Pull Request-> message "Please review branch-b."-> Send pull request

    You
        Receive email notification
            http://github.com-> sign in-> Pull requests-> All requests-> See branch-b-> read message-> exchange Q&A
             

Replicate untrusted partner's remote branch to a local branch on your laptop

    You
        git checkout master
            Switched to branch 'master'
        git branch seep-branch-b
        git checkout seep-branch-b
            Switched to a new branch 'branch-b'
        git remote add seep git@github.com:seep/testproj.git
        Confirm
            git remote -v
                github git@github.com:sag/testproj.git (fetch)
                github git@github.com:sag/testproj.git (push)
                seep git@github.com:seep/testproj.git (fetch)
                seep git@github.com:seep/testproj.git (push)
        git fetch seep
            remote: Counting objects: 5, done.
            remote: Compressing objects: 100% (1/1), done.
            remote: Total 3 (delta 1), reused 3 (delta 1)
            Unpacking objects: 100% (3/3), done.
            From github.com:seep/testproj
             * [new branch]      br4        -> seep/br4
             * [new branch]      branch-b   -> seep/branch-b
             * [new branch]      master     -> seep/master
        git merge seep/branch-b
            Updating 81e9140..b108f6f
            Fast-forward
            file1a.txt |    1 +
            1 files changed, 1 insertions(+), 0 deletions(-)
        Confirm
            cat file1a.txt
                file1a
                file1a modified by branch-b

Exchange emails with contributor...

Accept revisions from contributor to your local branch

    Untrusted partner
        echo "file1a..." >> file1a.txt
        git add file1a.txt
        git commit -m "file1a modified again..."
        git push github branch-b

    You
        git fetch seep
            remote: Counting objects: 5, done.
            remote: Compressing objects: 100% (2/2), done.
            remote: Total 3 (delta 1), reused 3 (delta 1)
            Unpacking objects: 100% (3/3), done.
            From github.com:seep/testproj
            a02a9d0..4aaf4fd  branch-b   -> seep/branch-b
        git rebase seep/branch-b
            First, rewinding head to replay your work on top of it...
            Fast-forwarded seep-branch-b to seep/branch-b.
        Confirm
            cat file0.txt
                file0
                change in branch master and in branch br2
                file0 modified by branch-b
                file0 modified again by branch-b

    Repeat

Also modify files in your own local branch, commit to local master, commit to github master

    You
        echo "file1a modified by seep-branch-b" >> file1a.txt
        git add file1a.txt
        git commit -m "file1a modified by seep-branch-b"
            [seep-branch-b 3989062] file1a modified by seep-branch-b
            1 files changed, 1 insertions(+), 0 deletions(-)

        git checkout master
            Switched to branch 'master'
        git diff seep-branch-b
            diff --git a/file1a.txt b/file1a.txt
            index 2529696..a7c50fe 100644
            --- a/file1a.txt
            +++ b/file1a.txt
            @@ -1,3 +1 @@
            file1a
            -file1a modified by branch-b
            -file1a modified by seep-branch-b
        git merge seep-branch-b
            Updating 81e9140..3989062
            Fast-forward
            file1a.txt |    2 ++
            1 files changed, 2 insertions(+), 0 deletions(-)
        Confirm
            cat file1a.txt
                file1a
                file1a modified by branch-b
                file1a modified by seep-branch-b

        git status
            # On branch master
            # Your branch is ahead of 'github/master' by 2 commits.
            #
            nothing to commit (working directory clean)
        git push github master
            Counting objects: 8, done.
            Delta compression using up to 2 threads.
            Compressing objects: 100% (5/5), done.
            Writing objects: 100% (6/6), 566 bytes, done.
            Total 6 (delta 2), reused 0 (delta 0)
            To git@github.com:sag/testproj.git
            81e9140..3989062  master -> master
        git branch -d seep-branch-b
            Deleted branch seep-branch-b (was 3989062).

Contributor fetches latest

    Untrusted partner:
        git checkout master
            Switched to branch 'master'
        Confirm
            cat file1a.txt
                file1a
        git remote add sag git@github.com:sag/testproj.git
        Confirm
            git remote -v
                github git@github.com:seep/testproj.git (fetch)
                github git@github.com:seep/testproj.git (push)
                sag git@github.com:sag/testproj.git (fetch)
                sag git@github.com:sag/testproj.git (push)
        git fetch sag
            remote: Counting objects: 5, done.
            remote: Compressing objects: 100% (3/3), done.
            remote: Total 3 (delta 1), reused 2 (delta 0)
            Unpacking objects: 100% (3/3), done.
            From github.com:sag/testproj
             * [new branch]      br4        -> sag/br4
             * [new branch]      master     -> sag/master
        git rebase sag/master
            First, rewinding head to replay your work on top of it...
            Fast-forwarded master to sag/master.
        Confirm
            cat file1a.txt
                file1a
                file1a modified by branch-b
                file1a modified by seep-branch-b
        Optional 1: upload from local branch master to github fork
            git push github master
                Counting objects: 5, done.
                Delta compression using up to 2 threads.
                Compressing objects: 100% (3/3), done.
                Writing objects: 100% (3/3), 304 bytes, done.
                Total 3 (delta 1), reused 0 (delta 0)
                To git@github.com:seep/testproj.git
                81e9140..3989062  master -> master
            Confirm
                http://github.com-> sign in-> list of files-> see file1a.txt
        Optional 2: delete branch at github
            git push github --delete branch-b
                To git@github.com:seep/testproj.git
                - [deleted]         branch-b
            Confirm:
                http://github.com-> sign in-> list of branches-> none
        Optional 3: delete local branch
            git branch -d branch-b
                Deleted branch branch-b (was b108f6f)
            Confirm
                git branch
                    * master

Step 8 of 8.  Collaboration with a Trusted Partner

    aka Shared Repository

    TBD - Watch this space...



References

    Posting SSH keys to github:  https://help.github.com/articles/generating-ssh-keys
    Using SSH config file:  http://nerderati.com/2011/03/simplify-your-life-with-an-ssh-config-file/
    Create a repository at Github:  https://help.github.com/articles/create-a-repo
    Fork a repository at Github:  https://help.github.com/articles/fork-a-repo
    Using pull requests:
        https://help.github.com/articles/using-pull-requests  (see "Fetch and Merge")
        http://effectif.com/git/applying-github-pull-requests
    All about Git (verbose):  http://git-scm.com/book
    All about Git (terse): http://gitref.org/
    Using shared repositories: http://toroid.org/ams/git-central-repo-howto
    Git pull vs fetch:
        http://stackoverflow.com/questions/292357/whats-the-difference-between-git-pull-and-git-fetch
        http://longair.net/blog/2009/04/16/git-fetch-and-merge/
    Deleting a repo:
        https://help.github.com/articles/deleting-a-repo
        http://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-in-github
    Adding multiple remotes:
        http://gitref.org/remotes/  ("take contributions from someone elses repository")

More references:
    http://www.sbf5.com/~cduan/technical/git/
    http://www.vogella.com/articles/Git/article.html
    Verbose details about git reset:  http://git-scm.com/2011/07/11/reset.html
    Team work procedures:  http://scottchacon.com/2011/08/31/github-flow.html

Too complex:
    http://www.gitguys.com/topics/tracking-branches-and-remote-tracking-branches/