Git.workflow
Git.workflow
Stashing
Making sure files are the correct mode
What to do when you get the dreaded editor
Stop tracking a remote branch
Squashing commits
Stackoverflow links
Initial setup
This command will create a directory named "someproject" in your home directory:
cd
git clone [email protected]:/git/someproject.git
cd someproject
Copy the .gitconfig file into your home directory and change the first two lines with your name and
email address!!
Nothing in this file is set in stone. We can discuss these settings as we get more comfortable with
git.
You might also want to set [core] editor, if you don't like nano.
Setup your ~/.bashrc. This provides a nice prompt that tells you what branch you're in at all times:
parse_git_branch () {
A=$(git status 2> /dev/null | head -n1 | cut -b13-)
[[ $A ]] && echo "(git::$A)"
}
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\
[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\] \[\033[31m\]$(parse_git_branch)\[\033[00m\]\$ '
. ~/.bashrc
I'm encouraging developers to use the pre-commit hook I wrote in their local devs. This hook
currently does 3 things:
• Ensures files are mode 644 except where needed. (With some path-based exceptions: Bin/,
tomcat6/bin/, and etc/hooks/git/)
• Does a lint check on php files.
• Checks for trailing commas in javascript data structures. (Although this was always an IE <=
8 thing, and we don't support IE <= 8 any more.)
Eventually this will become an update hook on origin, which means the 3 things above will be
enforced on push.
Work flow. A verbatim example (Long version)
We will be mostly following the work flow shown here: http://scottchacon.com/2011/08/31/github-
flow.html One exception is that we'll be using rebase instead of merge.
TL;DR: make a branch from master, work, commit, push the branch to the repo, rebase upstream
changes from master into the branch, work more, commit, push. When ready to test, checkout the
remote branch on a staging, pull, pull again when new changes are made to the branch. When ready
for release, merge to master, delete all local and remote branches, delete local tracking branches on
staging, prune.
First step, make a branch using the established naming convention (yourname/branchname):
$ cd someproject
$ git branch
* master
$ git pull
$ git checkout -b yourname/ticket_1234
Switched to a new branch 'yourname/ticket_1234'
$ git branch
* yourname/ticket_1234
master
Do some work:
$ vim path/to/someFile.whatever
$ git status
# On branch yourname/ticket_1234
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: path/to/someFile.whatever
#
no changes added to commit (use "git add" and/or "git commit -a")
When necessary, rebase from master to pull in upstream changes. Keep in mind that everything in
git is local, so pulling in upstream changes means getting published changes from the remote server
first...
Setup the branch to be tested in a staging environment. Again, keeping in mind that the local git
clone needs to become aware of what exists on the remote:
$ ssh staging.somedomain.com
...
...
$ cd someproject
Here's what a git fetch looks like when there's something new at the remote:
$ git fetch
remote: Counting objects: 53, done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 31 (delta 23), reused 0 (delta 0)
Unpacking objects: 100% (31/31), done.
From git.somedomain.com:/ebs/save/git/someproject
fee0139..2f48137 master -> origin/master
* [new branch] yourname/ticket_1234 -> origin/yourname/ticket_1234
Now checkout the branch as a branch that tracks against a remote repository:
Say further changes are necessary to complete the feature. Simply work more in your local dev:
$ $EDITOR path/to/someFile.whatever
$ git status
# On branch yourname/ticket_1234
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: path/to/someFile.whatever
#
no changes added to commit (use "git add" and/or "git commit -a")
Push the changes to the repo. Since this branch now exists in origin, you must do do things
differently if you're rebasing (which you should be)
First, rebase:
Now comes the special part. You must pull your origin branch before pushing, and use the --rebase
argument:
$ git push
Counting objects: 9, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 375 bytes, done.
Total 5 (delta 1), reused 0 (delta 0)
To [email protected]:/ebs/save/git/someproject.git
9c931f1..90d7cb3 yourname/ticket_1234 -> yourname/ticket_1234
$ ssh staging.somedomain.com
$ cd someproject
$ git fetch
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 5 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From git.somedomain.com:/ebs/save/git/someproject
9c931f1..90d7cb3 yourname/ticket_1234 -> origin/yourname/ticket_1234
$ git pull
Updating 9c931f1..90d7cb3
Fast-forward
path/to/someFile.whatever | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
And nuke the old remote branch (and yes, this syntax is weird):
Don't forget to delete the local branches in the testing environment as well, and to tell other
developers that might have created local branches that the remote branch no longer exists.
Rebase:
Repeat the above as necessary, just committing to your branch with "WIP" messages
Now you're ready to get this on staging. First make sure you've rebased to the latest master using
the instructions above.
. Now let's get rid of all the WIP commits first:
If you see files that don't need to be executable (0755) and they are, change them back to normal
(0644):
Since these changes came from a merge to master, I decided to amend the previous commit, which
was the actual merge. This way I don't also have a commit showing that I fixed file permissions:
At this point an editor came up with the last commit message, which I just accepted as-is. Here's the
output from the above command:
$ git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 6 and 1 different commit each, respectively.
# (use "git pull" to merge the remote branch into yours)
#
nothing to commit, working directory clean
$ git status
# On branch you/yourfeature
#
nothing to commit, working directory clean
$ git log
2a61c35 - (HEAD, you/yourfeature) work in progress (Mon Nov 3 15:33:41 2014 -0800) <Joe Bob>
7734fd3 - work in progress (Fri Oct 31 17:15:26 2014 -0700) <Joe Bob>
1fbb8dc - work in progress (Fri Oct 31 14:52:30 2014 -0700) <Joe Bob>
8b2f344 - work in progress (Fri Oct 31 14:34:32 2014 -0700) <Joe Bob>
e84e8bd - work in progress (Fri Oct 31 13:02:39 2014 -0700) <Joe Bob>
7798f8a - Merge branch 'master' into you/yourfeature (Thu Oct 30 23:44:18 2014 +0000) <Joe
Bob>
d4bda25 - work in progress (Thu Oct 30 16:39:30 2014 -0700) <Joe Bob>
ba320d6 - work in progress (Thu Oct 30 16:18:44 2014 -0700) <Joe Bob>
100a4e8 - work in progress (Thu Oct 30 15:38:48 2014 -0700) <Joe Bob>
...
But now it's time to merge your branch to master. Such commits should not be part of master, so
you should definitely clean things up. Make them all one nice big commit.
First, ensure that your branch is still "pristine", i.e., it only has the files you've changed. Start by
rebasing your branch, in case someone pushed a change to master between your morning rebase
and now, then:
Review the output above to ensure the list reflects only the files you know you changed in your
branch. Now reset your branch against your local master. What this will do is make you branch
appear as if you had never committed to it. Note that files you addded in the branch will show up as
untracked files:
$ git reset master
Unstaged changes after reset:
M somepath//css/crossover.css
M somepath//css/someproject.css
M somepath//cssPrint/culture_blocks.css
M somepath//cssold/cultureblocks.css
M somepath//js/LegendComponents.js
M somepath//js/PColorRampOptions.js
M somepath//js/PCube.js
M somepath//js/PMIdentificationModule.js
M somepath//js/PMap.js
M somepath//js/PPolyCreator.js
M somepath//js/PSession.js
M somepath//js/analytics.js
M somepath//js/z_cbclone/CBMapPageTypes.js
M somepath//js/z_cbclone/CBMatchPopup.js
M somepath//js/z_cbclone/CBPlaceSearchBox.js
M somepath//js/z_cbclone/CBProfileDropdowns.js
M somepath//js/z_cbclone/cultureblocks.js
M somepath//js/z_cbclone/report_generateCB.js
M somepath//js/z_cbclone/report_generate_cb.js
M somepath//js/z_cbclone/report_generate_wp.js
M somepath//main.jsp
D Web/someproject/templates/78/footer.php
D Web/someproject/templates/78/header.php
M Web/someproject/templates/78/index.php
D Web/someproject/templates/99/footer.php
D Web/someproject/templates/99/header.php
M Web/someproject/templates/99/report.php
M Web/someproject/templates/99/tool.php
M services/types/data/types/cbc.php
$ git status
# On branch you/yourfeature
#
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: somepath//css/crossover.css
# modified: somepath//css/someproject.css
# modified: somepath//cssPrint/culture_blocks.css
# modified: somepath//cssold/cultureblocks.css
# modified: somepath//js/LegendComponents.js
# modified: somepath//js/PColorRampOptions.js
# modified: somepath//js/PCube.js
# modified: somepath//js/PMIdentificationModule.js
# modified: somepath//js/PMap.js
# modified: somepath//js/PPolyCreator.js
# modified: somepath//js/PSession.js
# modified: somepath//js/analytics.js
# modified: somepath//js/z_cbclone/CBMapPageTypes.js
# modified: somepath//js/z_cbclone/CBMatchPopup.js
# modified: somepath//js/z_cbclone/CBPlaceSearchBox.js
# modified: somepath//js/z_cbclone/CBProfileDropdowns.js
# modified: somepath//js/z_cbclone/cultureblocks.js
# modified: somepath//js/z_cbclone/report_generateCB.js
# modified: somepath//js/z_cbclone/report_generate_cb.js
# modified: somepath//js/z_cbclone/report_generate_wp.js
# modified: somepath//main.jsp
# deleted: Web/someproject/templates/78/footer.php
# deleted: Web/someproject/templates/78/header.php
# modified: Web/someproject/templates/78/index.php
# deleted: Web/someproject/templates/99/footer.php
# deleted: Web/someproject/templates/99/header.php
# modified: Web/someproject/templates/99/report.php
# modified: Web/someproject/templates/99/tool.php
# modified: services/types/data/types/cbc.php
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# Web/someproject/templates/141/conf.php
# Web/someproject/templates/141/footer.php
# Web/someproject/templates/141/report.php
# Web/someproject/templates/141/tool.php
# Web/someproject/templates/99/conf.php
# Web/someproject/templates/cloneCommon/
#
no changes added to commit (use "git add" and/or "git commit -a")
What you now see are all the changes you've made to your branch since it was branched as
unstaged changes. You can now roll everything up into one clean commit (Note the . at the end of
the first command!):
Note this rewrites history in your branch. The copy of your branch in origin has now diverged from
this. But since this is the step you're performing before merging to master, you simply need to delete
the branch on origin after merging to master.