Workflow

Concepts

Repository

    • A repository (or "repo") holds "knowledge" about files in a Git format. This knowledge includes a complete file history including each commit for each file in the repo.

    • A repo can be local (e.g., on your laptop) or remote (e.g., on Github.com).

    • You can copy a remote repo to your local via git clone.

    • You can update a local repo via git fetch.

    • You can update a remote repo via git push.

Branches

    • A branch is a series of commits based off of each other.

    • Branches are switch between via the checkout command.

    • Branches can have tags, and I'm not exactly what what these are good for.

Remotes

    • A remote is a repository + branch.

    • You can define a remote via

Filesystem

    • These are the files that are in your directories

    • When you "checkout" code (in a branch), it goes onto your filesystem (in your working directory)

Workflow

1. Install and configure git

yum -y install git mkdir -p /opt/git cd /opt/ git config --global user.name "Justin G. Spratt" git config --global user.email "spratt.justin@gmail.com"

2. Get connected to Github

cd ~/.ssh/ ssh-keygen -t rsa -C "spratt.justin@gmail.com" # And follow the prompts. # Import your newly generated ssh key via github.com ssh -T git@github.com

Note: if you need to have your identity file (the output from ssh-keygen) named something other than id_rsa, you can setup a /root/.ssh/config file which selects to use a particular file per host (in this case, github.com). Cf. here.

Host github.com HostName github.com User git IdentityFile /root/.ssh/jgs-github

Part 2: Get connected to your repos

1. Check out the repos you want

  • git clone git@github.com:jgspratt/development.git

    • git branch -vv

    • master 792190f [origin/master] Merge pull request #311 from development/sprint-work

2. Get and update your remotes

    • git remote -v - Shows that you only have your private remote:

origin git@github.com:jgspratt/development.git (fetch) origin git@github.com:jgspratt/development.git (push)

  • git remote add upstream git@github.com:development/development.git

    • git remote -v Shows that you have upstream remotes:

origin git@github.com:jgspratt/development.git (fetch) origin git@github.com:jgspratt/development.git (push) upstream git@github.com:development/development.git (fetch) upstream git@github.com:development/development.git (push)

  • git fetch upstream

  • git branch -vv

master d562093 [origin/master] I am getting the scripts into Git. * sprint-work 3d3d2f5 [upstream/sprint-work] Merge pull request #311 from friend1/data-cleanup

    • Checkout the branch "sprint-work" (we just decided that on our own) from the repository known locally as "upstream" (git@github.com:development/development.git--we got that from git remote -v) to a local branch called "sprint-work." It is a good idea to keep your local branches named the same as you're remote branches.

    • git checkout -b sprint-work -t upstream/sprint-work

    • git status # Check that everything is clean

    • You may need to do something like this to get the right branch:

      • BRANCH='v1.1.12'

      • git checkout -b ${BRANCH} -t origin/${BRANCH}

    • # If it wasn't clean, you may need to rebase:

  • git rebase origin/${BRANCH}

    • # If a rebase doesn't work, you may need to start from scratch:

        • Info to come

Part 2 in summary:

    1. Add the remote (make your repo know about its existence) (then verify)

        1. git remote add upstream git@github.com:development/development.git

    2. Fetch the remote (make your repo know about its content)

        1. git fetch upstream

    1. Checkout the remote (deploy the latest files to your file system) (then verify)

        1. git checkout -b sprint-work -t upstream/sprint-work

Part 3: Daily Workflow I

    • Make a change to a file using your favorite text editor.

    • Tell git that the file should be included in a commit (use git commit -a in general to avoid these steps).

    • git status # Shows that git knows that it doesn't know to handle the file.

# On branch master # 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: hadoop-scripts/bin/scripts/export.sh # # Untracked files: # (use "git add <file>..." to include in what will be committed) # #hadoop-scripts/bin/database_exports/process.bat no changes added to commit (use "git add" and/or "git commit -a")

  • git add hadoop-scripts/bin/database_exports/process.bat

  • git status

# On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # #new file: hadoop-scripts/bin/database_exports/process.bat # # 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: hadoop-scripts/bin/database_exports/export.sh #

    • Save the file to your local repo (again, use git commit -a in general to avoid these steps).

      • git commit

    • Push the local repo to your private remote repo.

      • git push origin sprint-work:sprint-work

Counting objects: 366, done. Compressing objects: 100% (118/118), done. Writing objects: 100% (282/282), 71.99 KiB, done. Total 282 (delta 104), reused 269 (delta 101) To git@github.com:jgspratt/development.git d0f19d6..c881b50 sprint-work -> sprint-work

Here, we are saying "push the local branch called 'master' to the remote branch called 'master.'" The local branch is specified on the left and the remote branch is specified on the right.

At this point, you may be asking yourself, "Well, I see how I can specify branches on either side, but how do I specify repos? There is my private repo and then there is this 'sprint-work' thing called 'upstream.'" The trick is context. When you say git remote -v , you see what remote you currently have context of:

  • git remote -v

origin git@github.com:jgspratt/development.git (fetch) origin git@github.com:jgspratt/development.git (push) upstream git@github.com:development/development.git (fetch) upstream git@github.com:development/development.git (push)

And when we say git branch -vv, we see which branches we have context of (and which one, in fact, we are in the context of):

  • git branch -vv

master d522092 [origin/master] I am getting the scripts into Git. * sprint-work c886b50 [upstream/sprint-work: ahead 1] Exports to dropbox.

The things you cannot be in context of, as far as I know, are the remote branch (sprint-work, in this case) and the remote repo (origin, in this case). Those must be specified on the command line. However, being a fan of absolute paths which creates nice shell histories and context free pasting-and-running, I always prefer to put as much of the context that I already have into the command line. So, when I say to push my local sprint-work to the remote sprint-work, I didn't really have to specify the local sprint work, since I had it checked out and git sort of knew about that (hence the asterisk next to sprint-work in the previous block quote).

Here is a one-liner to add new files to Github

  • git add --all && git commit --all && git push origin sprint-work:sprint-work

Part 3 in summary:

    1. Add files to your local repo (make your local repo knows these files should be tracked)

      1. git add --all

    2. Commit to the remote (make your local repo know about the new files' content)

      1. git commit -a

    1. Push to the remote (push the local repo to the remote repo server)

      1. git push origin sprint-work:sprint-work

Part 4: Daily Workflow II

It's also important to be able to branch code and then merge it back in. Here's how we do that.

1. Get the new code things

  • git fetch origin

  • git status

    • If you see a note like the following, you may need to run a git merge --ff-only origin/master

    • Your branch is behind 'origin/master' by 9 commits, and can be fast-forwarded.

2. Make a new branch and check it out. When you execute the branch command, you will branch from your current branch.

    • git branch zabbix-backup

    • git checkout zabbix-backup

3. Make your code changes

mkdir -p /opt/git/configs/non-puppet/zabbix01/jgs/scripts-sysops/zabbix-backup/cron.d cd /opt/git/configs/non-puppet/zabbix01/jgs/scripts-sysops/zabbix-backup/ vim cron.d/zabbix-backup.cron vim zabbix-backup.sh vim install.sh vim uninstall.sh

4. Commit your changes

git add --all && git commit --all --message "" && git push origin zabbix-backup:zabbix-backup

5. Delete old branches (You will now have some extra branches, so you can delete those)

  • git branch -D zabbix-backup

Part 4: Daily Workflow III

1. On computer 1:

  • vim newfile

  • git add newfile && git commit && git push origin

2. On computer 2:

  • git clone

  • git pull

    • vim newfile # do something useless here

3. On computer 1:

    • vim newfile # do something useful here

  • git commit && git push origin

4. On computer 2 (you want the useful something you did in step 3, not the useless bit you did in step 2):

    • Here are several options.

    • git stash newfile # this is a simple option. not 100% clean

    • gitreset --hard HEAD # since you didn't commit, you can go back to the last commit.

        • Other options instead of HEAD are branch (local) and remote/branch

Commands

1. git clone - copy a remote repo to a local repo (they also call this "forking")

Copy git@github.com:jgspratt/configs.git to a local repo

  • git clone git@github.com:jgspratt/configs.git

2. git branch - change/list available branches

List very verbosely both remote-tracking and local branches

  • git branch -avv

Create a new branch

  • git branch new-branch

3. git fetch - update your local repo

Pull update all local repos with remote repos

  • git fetch

4. git remote - change/list your remote configuration

Define "jgs" as a remote pointing to git@github.com:jgspratt/configs.git

  • git remote add jgs git@github.com:jgspratt/configs.git

5. git checkout - export a repo to filesystem

Define "v1.1.10" (local) as "origin/v1.1.10" (remote) and populate working copy with the files from "origin/v1.1.10"

  • git checkout -b v1.1.10 -t origin/v1.1.10

6. git rebase - make your local source match the repo (+branch) source requested

    • git rebase <upstream> <branch>

        • Equivalent to git fetch && git rebase

        • Also equivalent to git pull --rebase

Deploy upstream/sprint-work to the file system (note: this will deploy only the local version of upstream/sprint-work, so make sure to fetch first):

  • git rebase upstream/sprint-work

7. git pull - Equivalent to git fetch && git merge (don't do this)

  • git pull

Appendix A: Prerequisites

CentOS

yum -y install git

Appendix B: Fancy Git

Fancy logs

    • Include in .bashrc: LESS="-R" (or say export LESS="-R" every time)

  • git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

  • git config --global color.ui auto

  • git config --global color.pager true

  • git config --global core.pager "less"

  • git lg

On Windows, this git lg works pretty well in Powershell:

lg = log --pretty=format:\"%h %ad | [%Cgreen%an%Creset] %s%d (%Cgreen%ar%Creset)\" --graph --date=short

This is the ultimate git log with diff:

lgd = log --color --pretty=format:'%C(cyan)--------------------------------------------------------------------------------%n%n%n%C(cyan)-------------------------------------------------------------------------------- %Creset%n%C(cyan)|%Creset Commit: %Cred%h%Creset / %H%n%C(cyan)|%Creset Author: %an %Cgreen<%ae>%Creset%n%C(cyan)|%Creset Date: %ai %Cgreen(%cr)%n%C(cyan)|%Creset Comment:%n%C(cyan)----------%n%B%C(cyan)----------%n%C(cyan)|%n%C(cyan)| Diff:%n%C(cyan)----------' -p

Fancy shell

    • Follow the instructions roughly on here.

  • git clone git://github.com/rtomayko/git-sh.git

  • cd git-sh

  • make

  • sudo make install

  • git-sh

  • git config --global color.sh auto

[Edit]