Jump to content

QESTNET Internal:Developer Git etiquette: Difference between revisions

From QESTonline
No edit summary
No edit summary
Line 1: Line 1:
== Initial Setup ==
== Initial Setup ==
#Signup for a GitHub account www.github.com. Tell someone your username so they can add you to the appropriate SpectraQEST team
*Signup for a GitHub account www.github.com. Tell someone your username so they can add you to the appropriate SpectraQEST team
#Download and install Git from http://git-scm.com/download. Windows has two possible ways to run git: choose msysgit instead of Cygwin. When installing, choose all the options that they recommend for Windows development. Install again to something like “C:\Program Files (x86)\Git”.
*Download and install Git from http://git-scm.com/download. Windows has two possible ways to run git: choose msysgit instead of Cygwin. When installing, choose all the options that they recommend for Windows development. Install again to something like “C:\Program Files (x86)\Git”.
*You will be prompted about line ending conversions at some point. Use the auto-convert option, I think it’s the first option. It should produce the line “autocrlf = true” in the default config: “C:\Program Files (x86)\Git\etc\gitconfig”.
**You will be prompted about line ending conversions at some point. Use the auto-convert option, I think it’s the first option. It should produce the line “autocrlf = true” in the default config: “C:\Program Files (x86)\Git\etc\gitconfig”.
#You can now:
*You can now:
*Run the Git console using Git Bash, a shortcut (quotes included): "C:\Program Files (x86)\Git\bin\sh.exe" --login –i
**Run the Git console using Git Bash, a shortcut (quotes included): "C:\Program Files (x86)\Git\bin\sh.exe" --login –i
*Run Git GUI using this entire command (quotes included) in a shortcut: "C:\Program Files (x86)\Git\bin\wish.exe" "C:\Program Files (x86)\Git\libexec\git-core\git-gui"
**Run Git GUI using this entire command (quotes included) in a shortcut: "C:\Program Files (x86)\Git\bin\wish.exe" "C:\Program Files (x86)\Git\libexec\git-core\git-gui"
*A shortcut for both of these should have been created in the Start Menu automatically.
**A shortcut for both of these should have been created in the Start Menu automatically.
#Your global Git configuration file “.gitconfig” is found under “C:\Users\Your.Name\.gitconfig”. Setup your username and email by using the following commands in Git Bash:
*Your global Git configuration file “.gitconfig” is found under “C:\Users\Your.Name\.gitconfig”. Setup your username and email by using the following commands in Git Bash:
*git config --global user.name “Your name”
**git config --global user.name “Your name”
*git config --global user.email your.name@spectraqest.com
**git config --global user.email your.name@spectraqest.com
#Download and install KDiff3 (this will be used as the merge tool for changes that can’t be automatically merged. Can maybe make it work with WinMerge, but haven’t tried.) This can be installed to the default location, something like “C:\Program Files (x86)\KDiff3”.
*Download and install KDiff3 (this will be used as the merge tool for changes that can’t be automatically merged. Can maybe make it work with WinMerge, but haven’t tried.) This can be installed to the default location, something like “C:\Program Files (x86)\KDiff3”.
#Setup Git to use KDiff3 and optionally Notepad++ as your editor instead of Vim by editing the global .gitconfig file. I find it easier to edit manually in Notepad++ than using the console. Here’s an example of a config file:
*Setup Git to use KDiff3 and optionally Notepad++ as your editor instead of Vim by editing the global .gitconfig file. I find it easier to edit manually in Notepad++ than using the console. Here’s an example of a config file:
 
<nowiki>[core]
[core]
editor = "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -nosession -noPlugin"
editor = "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -nosession -noPlugin"
autocrlf = true
autocrlf = true
Line 26: Line 25:
     tool = kdiff3
     tool = kdiff3
[difftool "kdiff3"]
[difftool "kdiff3"]
     path = c:/Program Files (x86)/KDiff3/kdiff3.exe
     path = c:/Program Files (x86)/KDiff3/kdiff3.exe</nowiki>
#Set up your public key: http://github.com/guides/providing-your-ssh-key . Note that the ~ directory in Git Bash corresponds to “C:\Users\Your.Name\”, so your SSH public key can be found in “C:\users\Your.Name\.ssh\id_rsa.pub” after you’ve generated it.
*Set up your public key: http://github.com/guides/providing-your-ssh-key . Note that the ~ directory in Git Bash corresponds to “C:\Users\Your.Name\”, so your SSH public key can be found in “C:\users\Your.Name\.ssh\id_rsa.pub” after you’ve generated it.
*By this point you will have a GitHub account and password, a private and public SSH key, and a password to access your private SSH key. This last password is just in case someone steals your computer, they cannot access your private key without a password. This prevents them from accessing anything you use your key for, such as GitHub, once you have added your public SSH key to GitHub.
**By this point you will have a GitHub account and password, a private and public SSH key, and a password to access your private SSH key. This last password is just in case someone steals your computer, they cannot access your private key without a password. This prevents them from accessing anything you use your key for, such as GitHub, once you have added your public SSH key to GitHub.
#Make the folder “C:\dev\” on your C Drive for development work.
*Make the folder “C:\dev\” on your C Drive for development work.
#Get a Git repository from GitHub via something like the following (note the URL comes from GitHub and changes depending on the project):
*Get a Git repository from GitHub via something like the following (note the URL comes from GitHub and changes depending on the project):
*cd /c/dev/
**cd /c/dev/
*git clone git@github.com:spectraqest/qestnet.upgrade.git
**git clone git@github.com:spectraqest/qestnet.upgrade.git
#That’s pretty much it. There are plenty of tools you can try out to assist with using Git if you wish. Two of the most popular are:
*That’s pretty much it. There are plenty of tools you can try out to assist with using Git if you wish. Two of the most popular are:
*GitHub for Windows: https://windows.github.com
**GitHub for Windows: https://windows.github.com
*Atlassian SourceTree: http://www.sourcetreeapp.com/
**Atlassian SourceTree: http://www.sourcetreeapp.com/
 
== How to "git" started ==
===Understanding Git===
Even I’ve only seen the tip of the iceberg, but there are some major conceptual differences with both VSS and SVN that are worth knowing.
<br><br>
There’s a couple of good resources that I like:
*Git Magic - http://www-cs-students.stanford.edu/~blynn/gitmagic/
*HgInit - http://hginit.com/top/ (Really well written, but actually for Mercurial, not Git. But the products are so similar that I found this one really useful anyway).
*Stack Overflow - http://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide (this question has a ton of links to other resources if you want them)
*Git Manual – you should be able to do “git help” from the command line to bring up the git manual.
The biggest difference between Git and VSS is VSS will create a local copy of a particular branch, but Git will create a copy of all of the branches as well as their entire histories. This means you can switch between them all without the server being involved. You can then change multiple branches and push all of them up to the server. You only ever “see” one branch at a time however, and switch between them using the “checkout” command. So instead of “checkin” and “checkout” going to and from the server, they are local commands. You then use push and fetch to go to and from the server. Google it, see the above links, or talk to one of us for more info.
===Command line vs. VS plugin===
Although there is a Git plugin for Visual Studio, I really don’t like it myself. Personally I think I’m getting along with Git much better with just the command line interface, which is faster in the long-run. So, once installed, I like to use “Git Bash” (available in the Start Menu). That opens up a Linux emulation, which I prefer because it has color-coding and shows your current branch etc; however, you can also run it directly from a Windows command line (assuming you installed Git with that option selected).
<br><br>
The main non-intuitive thing at first with Git Bash is that path names would be described like /c/dev/ and not “c:\dev\”.
===Hive in Git – Structure===
In theory, with only one version of the Hive ever live at a time, we should only need two branches: production (stable) and development. But for now, with the 0.7 and development branches so radically different, and 0.7 development still going on a bit, I’ve created independent branches for them both. We should be able to merge fairly easily between the branches anyway. If we need to later we might want to archive the 0.7 stuff away once we’re done with it. So, in short:
<br><br>
stable<br>
|-- dev<br>
|-- dev0.7<br>
<br>
Don’t ever work directly on the stable branch, for the obvious reason that it means you’re whacking new stuff directly into a branch that is supposed to be stable. Instead make your own branches under the dev branches as required and then, when you’re happy with it, merge it into the dev branches. More on the workflow later.
<br><br>
===App.config / web.config files===
As suggested by Lief a while ago, there’s also a better way to separate our app.config files, which I thought would go well with new source control. The technique is shown in the test-repository-net application on GitHub, though it’ll take a little bit of work to do it in Hive and I won’t worry about doing it in the 0.7 branch.
<br><br>
Basically, it allows us to store prod / test versions of configuration in source control, but allows our local development environment to use config that’s not in source control.
<br><br>
===How do I check out a file? (and branching)===
Two major points of difference with VSS here. One, individual files are not checked out, rather the entire tree is. Two, “checking out” really means switching to another branch. Though Git has a “checkout” command, it is not really like the VSS checkout at all.
<br><br>
Git is very big on branching, mainly because branching and merging are trivial in Git where they’re not in other SCMs. So you have not just the shared branches for separating stable and development code, but also you create them in your local repository to separate any particular line of work you might be following.
<br><br>
A branch is always on your entire working tree; in other words, any changes at all that you make while in the context of a branch apply to that branch. Making individual branches allows you to work on several different tasks at once without them interfering with each other. For example, a good approach is to have a separate branch for each issue that you’re working on. When you’re done working on the issue, you commit that whole branch.
<br><br>
Let’s say you’re working on a change to Program.cs, issue #5000. You might checkout a new branch just for working on that:
<br><br>
git branch 5000_program_fix
git checkout 5000_program_fix
<br><br>
(The above two commands can also be done with git checkout –b 5000_program_fix)
<br><br>
You start work on it, and modify Program.cs as you like. Suddenly, you’re told that issue #5055, a task to update the application readme.txt file, has to be done right away. So you commit your changes to the 5000_program_fix branch, and create a new branch for 5055_readme_fix.
notepad.exe Program.cs
git commit –a –m ‘Modified message on console main screen.’
git checkout –b 5055_readme_fix dev
(Note: if you don’t supply the starting point of master, the new branch (5055) will be created as a sub-branch of the current branch (5000), and will include all of the changes already committed for 5000.)
<br>
(Note 2: the “-a” in commit means “--all" and will automatically stage any changed files. See the git doco for more. It is not recommended unless you are sure you want all changed files included.)
<br><br>
You make the changes to the readme.txt and commit them.
notepad.exe readme.txt
git commit -a -m ‘Modified readme.txt with new instructions.’
Now you’ll find that you can switch between any of the three branches at will, and all of your work is separated correctly:
git checkout dev (contains neither the changes to Program.cs or readme.txt)
git checkout 5055_readme_fix (contains only the changes to the readme.txt)
git checkout 5000_program_fix (contains only the changes to Program.cs)
===How do I check in a file? (merging and pushing)===
Actually we sort of saw this in the previous question; we use git commit to “check in” a file to the current branch.
<br><br>
That’s not quite the end of the story though. For one, you’ve still got your changes in your own branch, like 5000_program_fix. So the first thing you should do once you’re happy with your fix is to merge it back into the development branch:
git checkout dev
git merge 5000_program_fix
If there are changes that can’t be automatically merged it should pop up the configured diff tool to let you do it manually. Otherwise, it just merges them in and automatically commits them (keeping your history of commits).
<br><br>
Remember, though, that this is all still occurring on your local repository; since you got the repository from GitHub, there’s been no communication at all with an external server. So, in order to put them back on the “central” repository:
git push origin dev
That will push all changes you’ve made to the dev branch up to the remote server.
<br><br>
Merging is a pretty common thing (just as common as branching really!). For example if a branch you’re working on needs a fix that you did in some other branch, just merge from that branch into the one you want.
===How do I see what I’ve changed?===
The easiest is to run Git Gui (or similar) and it will show you the changed files. If you want to use the console you can use:
git status
git status –u
See the manual for usage.
===Okay, but how do I see what’s changed in those files?===
In Git Gui, click on them. You can compare files in all sorts of ways, but most commonly may be between different branches, or different commits.
<br><br>
To view the differences in all of your uncommitted changes:
git diff
To view the differences in your uncommitted changes for a specific file:
git diff Program.cs
To view the differences between the master branch and the 5055 branch:
git diff master 5055_readme_fix
To view the differences between the current version and 2 commits ago:
git diff HEAD~2
There’s every other conceivable option you might need to compare too, those are just a very few basic ones.
<br><br>
You may also like to use the Git GUI for this, which provides a reasonably nice way of seeing complete file history of the entire repository – and generally much faster than SourceSafe does. Git GUI > Repository > Visualize … History.
<br><br>
Whoops, I made a mistake when committing! How do I undo it?
It’s quite alright to modify your own commits, since they still only exist in your own repository. The safest way is to use the reset command:
git reset --soft HEAD^
To explain: HEAD^ indicates that we should reset back to the state of the previous commit; if you wanted to go back two commits, you could use HEAD^^ or HEAD~2. The --soft reset means that the files themselves will not be modified, which is generally what you want; if you do a --hard reset instead, the files themselves will revert to the state they were in before you modified them, so only do that if you really want to throw away those changes.
<br><br>
After you’ve done a push it gets trickier because people may have pulled your mistake into their own repositories. In this case it’s generally recommended that you fix the mistake with another commit.
<br><br>
I need some cutting edge code that someone else is developing but which they haven’t pushed to the main repository. Can I get it?
Yes, you can pull from anyone’s repository, but I’m still working on the details of what’s required to allow our repositories to access each other. In the meantime, you could get the other person to push their branch up to the GitHub server and then you can pull from it.
===Git workflow===
The basic workflow I’d suggest for now is:
#Get the latest code if you think you need it. (git pull)
#Make sure you’re in the appropriate stable / dev branch (git checkout dev)
#Create a new branch (git branch fix_name)
#Checkout the new branch (git checkout fix_name)
#Make the required changes and test. Feel free to commit as you go.
#Review the files that you’ve changed, using git status and git diff.
#Add the modified files to the index and commit with a good message. (git commit –a –m ‘Commit message.’)
#Merge the fix into the development stream. (git checkout dev / git merge fix_name)
#Resolve any merge issues.
#Push the dev stream to the github repository. (git push origin dev)
 
There’s a huge amount of flexibility in how we can do the workflow, so what I’ve proposed is just a start. Later, once we’re used to the basic workflow, we can do things to ensure a nice commit history (using git rebase and/or git commit --squash) and other things that I’m not all that familiar with yet.
===Where’s my Tools > Options menu?===
You have Git configuration options at the individual repository level, or at a global level (i.e. applies to all repositories). These are stored in configuration files, but are most easily accessible via the command line. For example to see all settings applying to the current repository:
git config --list
Or if you want to see just your global settings:
git config --list --global
Then if you want to change a setting, just issue the name and new value:
git config core.autocrlf true
Again, if you’re changing a global setting, use the --global parameter. Repository-level settings will override global ones I think.
 
===I’ve made a whole ton of commits, but it makes for a pretty messy history. Can I clean it all up?===
Yes, the easiest way is to use the rebase command. This usage is most well described here: http://stackoverflow.com/questions/347901/what-are-your-favorite-git-features-or-tricks/2047707#2047707.
<br><br>
Also note Linus Torvalds’ recommendations with rebase, namely that you only rebase your own work: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html. Though product managers may want to clean up the code of their developers if absolutely necessary.
 
===Common Git Commands===
*git fetch – This will get the latest code from GitHub for all branches.
*git fetch <branchname> –  The same but for a specific branch.
*git checkout <branchname> –  Change to a specific branch on your local machine.
*git commit –  Create a new commit on your local machine.
*git commit –a –  Create a new commit on your local machine and automatically include all changed files. This will not add new files.
*git commit –m “message” –  Create a new commit on your local machine and use the supplied message for it.
*git commit --amend  – Change the message for the last commit you made.
*git push origin <branchname> –  Push changes for a specific branch to GitHub.
*git rebase <target_branchname> –  Rebase your currently checked out branch on top of the target branch.
*git rebase –i head~10 –  Rebase the last 10 commits interactively. This lets you change commit messages, re-order commits, squash multiple commits together, etc.
*git merge -–ff-only <branchname> –  A special type of merge just to update to more recent code.
*git mergetool –  Run the merge tool any time a rebase or merge fails and it needs manually consolidating.
 
===Merge vs Rebase:===
<nowiki>
Merge joins 2 branches together:
 
    A---B---C            branch 2
    /          \
D---E---F---G---H---      branch 1
 
 
Rebase (based on the above) applies the changes for one branch on top of another:
 
D---E---F---G---H---A---B---C---      branch 1, branch 2
</nowiki>


Because rebasing is destructive, this should not be done for code that has already been pushed up to GitHub. This is for reorganising commits on your local machine to make them nicer to push up.
<br><br>
This is most useful when you do a “git fetch” and discover someone else has pushed work up before you have. You then reapply your changes to the end of the history before pushing to GitHub.


== Starting on a new bug/change request ==
== Starting on a new bug/change request ==
#Checkout the development branch (e.g. alien) that the bug/change request will be added to.
*New branch
#Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
**Checkout the development branch (e.g. alien) that the bug/change request will be added to.
#Create a new branch using the bug/cr and some form of descriptor as the name (e.g. cr4321-tv-map or bug1234-tv-map-ucs).
**Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
#Make regular commits to this branch as you are developing.
**Create a new branch using the bug/cr and some form of descriptor as the name (e.g. cr4321-tv-map or bug1234-tv-map-ucs).
#Once initial development is complete rebase the bug/cr branch to a single commit.
*Development
#The bug/cr branch can now be pushed to github for testing.
**Make regular commits to this branch as you are developing.
#The tester will fetch and checkout the cr/bug branch to test it and give feedback.
**Once initial development is complete rebase the bug/cr branch to a single commit.
#At this point make any required changes on the branch. Commit and push to github so that the tester can re-test.
**The bug/cr branch can now be pushed to github for testing.
#Once all development is complete, checkout the development branch again. Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
*Testing
#Merge the bug/cr branch into the development branch, resolving any conflicts.
**The tester will fetch and checkout the cr/bug branch to test it and give feedback.
#The development branch can now be pushed to github for integration testing.
**At this point make any required changes on the branch. Commit and push to github so that the tester can re-test.
#Minor fixes required from integration testing can be made directly on the development branch. Any major problems development can revert back to the bug/cr branch.
**Once all development is complete, checkout the development branch again. Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
#Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github.
**Merge the bug/cr branch into the development branch, resolving any conflicts.
**The development branch can now be pushed to github for integration testing.
*Integration Testing
**Minor fixes required from integration testing can be made directly on the development branch. Any major problems development can revert back to the bug/cr branch.
**Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github.

Revision as of 06:41, 15 July 2015

Initial Setup

  • Signup for a GitHub account www.github.com. Tell someone your username so they can add you to the appropriate SpectraQEST team
  • Download and install Git from http://git-scm.com/download. Windows has two possible ways to run git: choose msysgit instead of Cygwin. When installing, choose all the options that they recommend for Windows development. Install again to something like “C:\Program Files (x86)\Git”.
    • You will be prompted about line ending conversions at some point. Use the auto-convert option, I think it’s the first option. It should produce the line “autocrlf = true” in the default config: “C:\Program Files (x86)\Git\etc\gitconfig”.
  • You can now:
    • Run the Git console using Git Bash, a shortcut (quotes included): "C:\Program Files (x86)\Git\bin\sh.exe" --login –i
    • Run Git GUI using this entire command (quotes included) in a shortcut: "C:\Program Files (x86)\Git\bin\wish.exe" "C:\Program Files (x86)\Git\libexec\git-core\git-gui"
    • A shortcut for both of these should have been created in the Start Menu automatically.
  • Your global Git configuration file “.gitconfig” is found under “C:\Users\Your.Name\.gitconfig”. Setup your username and email by using the following commands in Git Bash:
    • git config --global user.name “Your name”
    • git config --global user.email your.name@spectraqest.com
  • Download and install KDiff3 (this will be used as the merge tool for changes that can’t be automatically merged. Can maybe make it work with WinMerge, but haven’t tried.) This can be installed to the default location, something like “C:\Program Files (x86)\KDiff3”.
  • Setup Git to use KDiff3 and optionally Notepad++ as your editor instead of Vim by editing the global .gitconfig file. I find it easier to edit manually in Notepad++ than using the console. Here’s an example of a config file:
[core]
	editor = "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -nosession -noPlugin"
	autocrlf = true
[user]
	name = John Meegan
	email = john.meegan@spectraqest.com
[merge]
    tool = kdiff3
[mergetool "kdiff3"]
    path = c:/Program Files (x86)/KDiff3/kdiff3.exe
[diff]
    tool = kdiff3
[difftool "kdiff3"]
    path = c:/Program Files (x86)/KDiff3/kdiff3.exe
  • Set up your public key: http://github.com/guides/providing-your-ssh-key . Note that the ~ directory in Git Bash corresponds to “C:\Users\Your.Name\”, so your SSH public key can be found in “C:\users\Your.Name\.ssh\id_rsa.pub” after you’ve generated it.
    • By this point you will have a GitHub account and password, a private and public SSH key, and a password to access your private SSH key. This last password is just in case someone steals your computer, they cannot access your private key without a password. This prevents them from accessing anything you use your key for, such as GitHub, once you have added your public SSH key to GitHub.
  • Make the folder “C:\dev\” on your C Drive for development work.
  • Get a Git repository from GitHub via something like the following (note the URL comes from GitHub and changes depending on the project):
    • cd /c/dev/
    • git clone git@github.com:spectraqest/qestnet.upgrade.git
  • That’s pretty much it. There are plenty of tools you can try out to assist with using Git if you wish. Two of the most popular are:

How to "git" started

Understanding Git

Even I’ve only seen the tip of the iceberg, but there are some major conceptual differences with both VSS and SVN that are worth knowing.

There’s a couple of good resources that I like:

The biggest difference between Git and VSS is VSS will create a local copy of a particular branch, but Git will create a copy of all of the branches as well as their entire histories. This means you can switch between them all without the server being involved. You can then change multiple branches and push all of them up to the server. You only ever “see” one branch at a time however, and switch between them using the “checkout” command. So instead of “checkin” and “checkout” going to and from the server, they are local commands. You then use push and fetch to go to and from the server. Google it, see the above links, or talk to one of us for more info.

Command line vs. VS plugin

Although there is a Git plugin for Visual Studio, I really don’t like it myself. Personally I think I’m getting along with Git much better with just the command line interface, which is faster in the long-run. So, once installed, I like to use “Git Bash” (available in the Start Menu). That opens up a Linux emulation, which I prefer because it has color-coding and shows your current branch etc; however, you can also run it directly from a Windows command line (assuming you installed Git with that option selected).

The main non-intuitive thing at first with Git Bash is that path names would be described like /c/dev/ and not “c:\dev\”.

Hive in Git – Structure

In theory, with only one version of the Hive ever live at a time, we should only need two branches: production (stable) and development. But for now, with the 0.7 and development branches so radically different, and 0.7 development still going on a bit, I’ve created independent branches for them both. We should be able to merge fairly easily between the branches anyway. If we need to later we might want to archive the 0.7 stuff away once we’re done with it. So, in short:

stable
|-- dev
|-- dev0.7

Don’t ever work directly on the stable branch, for the obvious reason that it means you’re whacking new stuff directly into a branch that is supposed to be stable. Instead make your own branches under the dev branches as required and then, when you’re happy with it, merge it into the dev branches. More on the workflow later.

App.config / web.config files

As suggested by Lief a while ago, there’s also a better way to separate our app.config files, which I thought would go well with new source control. The technique is shown in the test-repository-net application on GitHub, though it’ll take a little bit of work to do it in Hive and I won’t worry about doing it in the 0.7 branch.

Basically, it allows us to store prod / test versions of configuration in source control, but allows our local development environment to use config that’s not in source control.

How do I check out a file? (and branching)

Two major points of difference with VSS here. One, individual files are not checked out, rather the entire tree is. Two, “checking out” really means switching to another branch. Though Git has a “checkout” command, it is not really like the VSS checkout at all.

Git is very big on branching, mainly because branching and merging are trivial in Git where they’re not in other SCMs. So you have not just the shared branches for separating stable and development code, but also you create them in your local repository to separate any particular line of work you might be following.

A branch is always on your entire working tree; in other words, any changes at all that you make while in the context of a branch apply to that branch. Making individual branches allows you to work on several different tasks at once without them interfering with each other. For example, a good approach is to have a separate branch for each issue that you’re working on. When you’re done working on the issue, you commit that whole branch.

Let’s say you’re working on a change to Program.cs, issue #5000. You might checkout a new branch just for working on that:

git branch 5000_program_fix
git checkout 5000_program_fix



(The above two commands can also be done with git checkout –b 5000_program_fix)

You start work on it, and modify Program.cs as you like. Suddenly, you’re told that issue #5055, a task to update the application readme.txt file, has to be done right away. So you commit your changes to the 5000_program_fix branch, and create a new branch for 5055_readme_fix.

notepad.exe Program.cs
git commit –a –m ‘Modified message on console main screen.’
git checkout –b 5055_readme_fix dev

(Note: if you don’t supply the starting point of master, the new branch (5055) will be created as a sub-branch of the current branch (5000), and will include all of the changes already committed for 5000.)
(Note 2: the “-a” in commit means “--all" and will automatically stage any changed files. See the git doco for more. It is not recommended unless you are sure you want all changed files included.)

You make the changes to the readme.txt and commit them.

notepad.exe readme.txt
git commit -a -m ‘Modified readme.txt with new instructions.’

Now you’ll find that you can switch between any of the three branches at will, and all of your work is separated correctly:

git checkout dev (contains neither the changes to Program.cs or readme.txt)
git checkout 5055_readme_fix (contains only the changes to the readme.txt)
git checkout 5000_program_fix (contains only the changes to Program.cs)

How do I check in a file? (merging and pushing)

Actually we sort of saw this in the previous question; we use git commit to “check in” a file to the current branch.

That’s not quite the end of the story though. For one, you’ve still got your changes in your own branch, like 5000_program_fix. So the first thing you should do once you’re happy with your fix is to merge it back into the development branch:

git checkout dev
git merge 5000_program_fix

If there are changes that can’t be automatically merged it should pop up the configured diff tool to let you do it manually. Otherwise, it just merges them in and automatically commits them (keeping your history of commits).

Remember, though, that this is all still occurring on your local repository; since you got the repository from GitHub, there’s been no communication at all with an external server. So, in order to put them back on the “central” repository:

git push origin dev

That will push all changes you’ve made to the dev branch up to the remote server.

Merging is a pretty common thing (just as common as branching really!). For example if a branch you’re working on needs a fix that you did in some other branch, just merge from that branch into the one you want.

How do I see what I’ve changed?

The easiest is to run Git Gui (or similar) and it will show you the changed files. If you want to use the console you can use:

git status
git status –u

See the manual for usage.

Okay, but how do I see what’s changed in those files?

In Git Gui, click on them. You can compare files in all sorts of ways, but most commonly may be between different branches, or different commits.

To view the differences in all of your uncommitted changes:

git diff

To view the differences in your uncommitted changes for a specific file:

git diff Program.cs

To view the differences between the master branch and the 5055 branch:

git diff master 5055_readme_fix

To view the differences between the current version and 2 commits ago:

git diff HEAD~2

There’s every other conceivable option you might need to compare too, those are just a very few basic ones.

You may also like to use the Git GUI for this, which provides a reasonably nice way of seeing complete file history of the entire repository – and generally much faster than SourceSafe does. Git GUI > Repository > Visualize … History.

Whoops, I made a mistake when committing! How do I undo it? It’s quite alright to modify your own commits, since they still only exist in your own repository. The safest way is to use the reset command:

git reset --soft HEAD^

To explain: HEAD^ indicates that we should reset back to the state of the previous commit; if you wanted to go back two commits, you could use HEAD^^ or HEAD~2. The --soft reset means that the files themselves will not be modified, which is generally what you want; if you do a --hard reset instead, the files themselves will revert to the state they were in before you modified them, so only do that if you really want to throw away those changes.

After you’ve done a push it gets trickier because people may have pulled your mistake into their own repositories. In this case it’s generally recommended that you fix the mistake with another commit.

I need some cutting edge code that someone else is developing but which they haven’t pushed to the main repository. Can I get it? Yes, you can pull from anyone’s repository, but I’m still working on the details of what’s required to allow our repositories to access each other. In the meantime, you could get the other person to push their branch up to the GitHub server and then you can pull from it.

Git workflow

The basic workflow I’d suggest for now is:

  1. Get the latest code if you think you need it. (git pull)
  2. Make sure you’re in the appropriate stable / dev branch (git checkout dev)
  3. Create a new branch (git branch fix_name)
  4. Checkout the new branch (git checkout fix_name)
  5. Make the required changes and test. Feel free to commit as you go.
  6. Review the files that you’ve changed, using git status and git diff.
  7. Add the modified files to the index and commit with a good message. (git commit –a –m ‘Commit message.’)
  8. Merge the fix into the development stream. (git checkout dev / git merge fix_name)
  9. Resolve any merge issues.
  10. Push the dev stream to the github repository. (git push origin dev)

There’s a huge amount of flexibility in how we can do the workflow, so what I’ve proposed is just a start. Later, once we’re used to the basic workflow, we can do things to ensure a nice commit history (using git rebase and/or git commit --squash) and other things that I’m not all that familiar with yet.

Where’s my Tools > Options menu?

You have Git configuration options at the individual repository level, or at a global level (i.e. applies to all repositories). These are stored in configuration files, but are most easily accessible via the command line. For example to see all settings applying to the current repository:

git config --list

Or if you want to see just your global settings:

git config --list --global

Then if you want to change a setting, just issue the name and new value:

git config core.autocrlf true

Again, if you’re changing a global setting, use the --global parameter. Repository-level settings will override global ones I think.

I’ve made a whole ton of commits, but it makes for a pretty messy history. Can I clean it all up?

Yes, the easiest way is to use the rebase command. This usage is most well described here: http://stackoverflow.com/questions/347901/what-are-your-favorite-git-features-or-tricks/2047707#2047707.

Also note Linus Torvalds’ recommendations with rebase, namely that you only rebase your own work: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html. Though product managers may want to clean up the code of their developers if absolutely necessary.

Common Git Commands

  • git fetch – This will get the latest code from GitHub for all branches.
  • git fetch <branchname> – The same but for a specific branch.
  • git checkout <branchname> – Change to a specific branch on your local machine.
  • git commit – Create a new commit on your local machine.
  • git commit –a – Create a new commit on your local machine and automatically include all changed files. This will not add new files.
  • git commit –m “message” – Create a new commit on your local machine and use the supplied message for it.
  • git commit --amend – Change the message for the last commit you made.
  • git push origin <branchname> – Push changes for a specific branch to GitHub.
  • git rebase <target_branchname> – Rebase your currently checked out branch on top of the target branch.
  • git rebase –i head~10 – Rebase the last 10 commits interactively. This lets you change commit messages, re-order commits, squash multiple commits together, etc.
  • git merge -–ff-only <branchname> – A special type of merge just to update to more recent code.
  • git mergetool – Run the merge tool any time a rebase or merge fails and it needs manually consolidating.

Merge vs Rebase:

Merge joins 2 branches together: A---B---C branch 2 / \ D---E---F---G---H--- branch 1 Rebase (based on the above) applies the changes for one branch on top of another: D---E---F---G---H---A---B---C--- branch 1, branch 2

Because rebasing is destructive, this should not be done for code that has already been pushed up to GitHub. This is for reorganising commits on your local machine to make them nicer to push up.

This is most useful when you do a “git fetch” and discover someone else has pushed work up before you have. You then reapply your changes to the end of the history before pushing to GitHub.

Starting on a new bug/change request

  • New branch
    • Checkout the development branch (e.g. alien) that the bug/change request will be added to.
    • Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
    • Create a new branch using the bug/cr and some form of descriptor as the name (e.g. cr4321-tv-map or bug1234-tv-map-ucs).
  • Development
    • Make regular commits to this branch as you are developing.
    • Once initial development is complete rebase the bug/cr branch to a single commit.
    • The bug/cr branch can now be pushed to github for testing.
  • Testing
    • The tester will fetch and checkout the cr/bug branch to test it and give feedback.
    • At this point make any required changes on the branch. Commit and push to github so that the tester can re-test.
    • Once all development is complete, checkout the development branch again. Pull or fetch from github the latest of the branch and ensure that your local copy is at the head.
    • Merge the bug/cr branch into the development branch, resolving any conflicts.
    • The development branch can now be pushed to github for integration testing.
  • Integration Testing
    • Minor fixes required from integration testing can be made directly on the development branch. Any major problems development can revert back to the bug/cr branch.
    • Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github.