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:
Add the remote (make your repo know about its existence) (then verify)
git remote add upstream git@github.com:development/development.git
Fetch the remote (make your repo know about its content)
git fetch upstream
Checkout the remote (deploy the latest files to your file system) (then verify)
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:
Add files to your local repo (make your local repo knows these files should be tracked)
git add --all
Commit to the remote (make your local repo know about the new files' content)
git commit -a
Push to the remote (push the local repo to the remote repo server)
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