0% found this document useful (0 votes)
2 views

Git.workflow

This document outlines a comprehensive Git workflow, including initial setup, branching, rebasing, and merging processes. It emphasizes the importance of using a pre-commit hook for file mode checks and linting, as well as provides detailed commands for managing branches and handling common issues like editor prompts during merges. Additionally, it offers a shorter version of the workflow for quick reference, along with troubleshooting tips for common Git scenarios.

Uploaded by

vicos23
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Git.workflow

This document outlines a comprehensive Git workflow, including initial setup, branching, rebasing, and merging processes. It emphasizes the importance of using a pre-commit hook for file mode checks and linting, as well as provides detailed commands for managing branches and handling common issues like editor prompts during merges. Additionally, it offers a shorter version of the workflow for quick reference, along with troubleshooting tips for common Git scenarios.

Uploaded by

vicos23
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

GIT!

Work Flow (Long version)


Work Flow (Short version)

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\]\$ '

Source the ~/.bashrc in the current terminal:

. ~/.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")

Commit the work to the branch:

$ git commit -a -m "Updated somefile.whatever to operate at 1.21 giggawatts."


[yourname/ticket_1234 b208db7] Updated somefile.whatever to operate at 1.21 giggawatts.
1 file changed, 1 insertion(+)

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...

$ git checkout master


$ git pull

...and now rebase your branch:

$ git checkout yourname/ticket_1234


$ git rebase master
Since nothing's been pushed to origin yet, nothing else needs to be done.
Push the branch to the repo to make it available for testing, or for other developers. This will also
serve to back up our work in a separate location:

$ git push -u origin yourname/ticket_1234


Counting objects: 9, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 641 bytes, done.
Total 7 (delta 2), reused 0 (delta 0)
To [email protected]:/ebs/save/git/someproject.git
* [new branch] yourname/ticket_1234 -> yourname/ticket_1234
Branch yourname/ticket_1234 set up to track remote branch yourname/ticket_1234 from origin.

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:

$ git checkout -b yourname/ticket_1234 origin/yourname/ticket_1234


Branch yourname/ticket_1234 set up to track remote branch yourname/ticket_1234 from origin.
Switched to a new branch 'yourname/ticket_1234'

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")

Commit the new changes:


$ git commit -a -m "Adjust the flux capacitor."
[ticket_yourname/1234 90d7cb3] Adjust the flux capacitor.
1 file changed, 1 insertion(+), 1 deletion(-)

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:

$ git checkout master


$ git pull
$ git checkout yourname/ticket_1234
$ git rebase master

Now comes the special part. You must pull your origin branch before pushing, and use the --rebase
argument:

$ git pull --rebase

Now you can push the new changes up to origin:

$ 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

Update the branch on the staging environment:

$ 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(-)

Once the feature's fully tested and approved, merge it to master:

$ git checkout master


Switched to branch 'master'
$ git merge yourname/ticket_1234
Updating 7313165..0a41a22
Fast-forward
path/to/someFile.whatever | 1 -
1 file changed, 1 deletion(-)
$ git push
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 357 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To [email protected]:/ebs/save/git/someproject.git
2f48137..03825db master -> master

Nuke the old local feature branch:

$ git branch -D yourname/ticket_1234


Deleted branch yourname/ticket_1234 (was 0a41a22).

And nuke the old remote branch (and yes, this syntax is weird):

$ git push origin :yourname/ticket_1234


To [email protected]:/ebs/save/git/someproject.git
- [deleted] yourname/ticket_1234

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.

It might be necessary to prune stale branches from the repo. If this...

git remote show origin

...shows a stale branch, do this:

git remote prune origin

Work flow. A verbatim example (Short version)


Just going to cover what should happen locally in your dev. Refer to the long version for updating
staging.

$ git checkout master


$ git pull
$ git checkout -b yourname/ticket_1234

Now do some work.


Now say upstream changes have come in, so rebase.
First, commit your work in progress:

$ git add --all


$ git commit -m "WIP"

Rebase:

$ git checkout master


$ git pull
$ git checkout yourname/ticket_1234
$ git rebase master

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:

$ git reset master


$ git add --all
$ git commit -m "Implemented an adjustment to the master cylinder."

Now push your branch up to origin:

$ git push -u origin yourname/ticket_1234

Connect to staging and checkout the branch there.


A bug was found, so now you need to keep working, but you need to rebase your branch first. Now
that it's been pushed, you need to perform an extra step before pushing:

$ git checkout master


$ git pull
$ git checkout yourname/ticket_1234
$ git rebase master
$ git pull --rebase
$ git push

Concepts (Work in progress below here)


Started working on files before creating a branch? NO PROBLEM!
$ git status
# On branch master
# 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: Bin/tcbuild.sh
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git stash
Saved working directory and index state WIP on master: 4498b49 Make empty directories in the
build script.
HEAD is now at 4498b49 Make empty directories in the build script.
$ git checkout -b featureX
Switched to a new branch 'featureX'
$ git status
# On branch featureX
nothing to commit (working directory clean)
$ git stash pop
# On branch featureX
# 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: Bin/tcbuild.sh
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (854ffbde443f160e92d0f77e4764911aab55c57b)

Ensure file modes don't change when not necessary


For example:

20 files changed, 220 insertions(+), 271 deletions(-)


mode change 100644 => 100755 somepath//css/reports.css
mode change 100644 => 100755 somepath//js/TaxonomyMenu.js
rename somepath//js/{custom_regions => }/TrfCustomRegionsMenu.js (75%)
mode change 100644 => 100755
delete mode 100644 Web/someproject/templates/common/custom_regions.php

If you see files that don't need to be executable (0755) and they are, change them back to normal
(0644):

$ chmod 644 somepath//css/reports.css


$ chmod 644 somepath//js/TaxonomyMenu.js
$ chmod 644 somepath//js/TrfCustomRegionsMenu.js
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 14 commits.
#
# 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: somepath//css/reports.css
# modified: somepath//js/TaxonomyMenu.js
# modified: somepath//js/TrfCustomRegionsMenu.js
#
no changes added to commit (use "git add" and/or "git commit -a")

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:

$ git commit -a --amend

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:

[master 9a84011] Merge branch 'ticket-7398-and-others' of


git.somedomain.com:/ebs/save/git/someproject into ticket-7398-and-others

Fucking editor comes up when you pull


$ git pull
--- Fucking editor comes up!!
You must save an empty file at this point! A file with contents has been written, and the default
editor opened to this file. You must now empty the file out and save an empty file. Once you exit the
editor, you will now see something like this:

remote: Counting objects: 13, done.


remote: Compressing objects: 100% (7/7), done.
remote: Total 7 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
From git.somedomain.com:/ebs/save/git/someproject
+ 2fdb448...b2783b7 master -> origin/master (forced update)
error: Empty commit message.
Not committing merge; use 'git commit' to complete the merge.

Since a pull is also a merge, you abort the merge:

$ git merge --abort

Which will leave things looking like this:

$ 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

Now you just need to pull with the rebase option:

$ git pull --rebase


First, rewinding head to replay your work on top of it...

Et voilà! Everything's back to normal.

Delete a remote branch and stop tracking it


First delete the remote branch

$ git push origin :you/yourbranch


To [email protected]:/ebs/save/git/someproject.git
- [deleted] you/yourbranch

Now stop tracking it

$ git config --unset branch.you/yourbranch.remote


$ git config --unset branch.you/yourbranch.merge

Squashing many commits into one


Say you do a lot of WIP (Work In Progress) commits into your branch:

$ 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:

$ git diff master --name-only


somepath//css/crossover.css
somepath//css/someproject.css
somepath//cssPrint/culture_blocks.css
somepath//cssold/cultureblocks.css
somepath//js/LegendComponents.js
somepath//js/PColorRampOptions.js
somepath//js/PCube.js
somepath//js/PMIdentificationModule.js
somepath//js/PMap.js
somepath//js/PPolyCreator.js
somepath//js/PSession.js
somepath//js/analytics.js
somepath//js/z_cbclone/CBMapPageTypes.js
somepath//js/z_cbclone/CBMatchPopup.js
somepath//js/z_cbclone/CBPlaceSearchBox.js
somepath//js/z_cbclone/CBProfileDropdowns.js
somepath//js/z_cbclone/cultureblocks.js
somepath//js/z_cbclone/report_generateCB.js
somepath//js/z_cbclone/report_generate_cb.js
somepath//js/z_cbclone/report_generate_wp.js
somepath//main.jsp
Web/someproject/templates/78/footer.php
Web/someproject/templates/78/header.php
Web/someproject/templates/78/index.php
Web/someproject/templates/99/footer.php
Web/someproject/templates/99/header.php
Web/someproject/templates/99/report.php
Web/someproject/templates/99/tool.php
services/types/data/types/cbc.php

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!):

$ git add --all .


...
$ git commit -m "Implemented myfeature bla bla bla bla..."
...

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.

Accidentally committed to the wrong branch and already pushed?


http://stackoverflow.com/questions/6459080/how-can-i-remove-git-commit-after-git-push

Merge vs. Rebase


http://mislav.uniqpath.com/2013/02/merge-vs-rebase/

How to rename a local branch


http://stackoverflow.com/questions/6591213/how-to-rename-local-branch

How to delete a commit once you're made other commits after it


http://stackoverflow.com/questions/1338728/delete-commits-from-a-branch-in-
git/1338756#1338756
More to come...

You might also like