QESTNET Internal:Developer Git etiquette: Difference between revisions
David.lucas (talk | contribs) No edit summary |
David.lucas (talk | contribs) No edit summary |
||
| (6 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
===Starting | == 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\”. | |||
===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: | |||
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) | |||
<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. | |||
===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:=== | |||
Merge joins 2 branches together: | |||
<nowiki> | |||
A---B---C branch 2 | |||
/ \ | |||
D---E---F---G---H--- branch 1 | |||
</nowiki> | |||
Rebase (based on the above) applies the changes for one branch on top of another: | |||
<nowiki> | |||
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. | |||
==Git workflow== | |||
===Starting a new bug/change request=== | |||
*Checkout the development branch (e.g. alien) that the bug/change request will be added to. | *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. | **Pull or fetch from github the latest of the branch and ensure that your local copy is at the head (git pull origin alien or git fetch origin alien and git merge --ff-only origin/alien). | ||
*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). | **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). | ||
*Make regular commits to this branch as you are developing. | **Checkout the new branch (git checkout cr4321-tv-map). | ||
*Once initial development is complete rebase the bug/cr branch to a single commit. | *Make regular commits to this branch as you are developing (git commit -a -m 'Commit message.'). | ||
*The bug/cr branch can now be pushed to github for testing. | **Once initial development is complete rebase the bug/cr branch to a single commit (git rebase -i origin/cr4321-tv-map). | ||
**Review the files that you’ve changed, using git status and git diff to ensure there are no unexpected changes. | |||
**The bug/cr branch can now be pushed to github for testing (git push origin cr4321-tv-map). | |||
*The tester will fetch and checkout the cr/bug branch to test it and give feedback. | *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. | **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. | **Once all development is complete, checkout the development branch again (git checkout alien). Pull or fetch from github the latest of the branch and ensure that your local copy is at the head (git pull origin alien). | ||
*Merge the bug/cr branch into the development branch, resolving any conflicts. | **Merge the bug/cr branch into the development branch, resolving any conflicts (git merge cr4321-tv-map). | ||
*The development branch can now be pushed to github for integration testing. | **The development branch can now be pushed to github for integration testing (git push origin alien). | ||
*Minor fixes required from integration testing can be made directly on the development branch. | *The tester will fetch and checkout the development branch to test it and give feedback. | ||
*Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github. | **Minor fixes required from integration testing can be made directly on the development branch. These should be no major problems but if there are the fixes should be made on the bug/cr branch and tested there first. This should be done with priority as the development branch may be "broken" until these changes are merged. | ||
**Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github. | |||
Latest revision as of 07:12, 15 July 2015
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:
- 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).
The main non-intuitive thing at first with Git Bash is that path names would be described like /c/dev/ and not “c:\dev\”.
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.
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.
Git workflow
Starting a new bug/change request
- 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 (git pull origin alien or git fetch origin alien and git merge --ff-only origin/alien).
- 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).
- Checkout the new branch (git checkout cr4321-tv-map).
- Make regular commits to this branch as you are developing (git commit -a -m 'Commit message.').
- Once initial development is complete rebase the bug/cr branch to a single commit (git rebase -i origin/cr4321-tv-map).
- Review the files that you’ve changed, using git status and git diff to ensure there are no unexpected changes.
- The bug/cr branch can now be pushed to github for testing (git push origin cr4321-tv-map).
- 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 (git checkout alien). Pull or fetch from github the latest of the branch and ensure that your local copy is at the head (git pull origin alien).
- Merge the bug/cr branch into the development branch, resolving any conflicts (git merge cr4321-tv-map).
- The development branch can now be pushed to github for integration testing (git push origin alien).
- The tester will fetch and checkout the development branch to test it and give feedback.
- Minor fixes required from integration testing can be made directly on the development branch. These should be no major problems but if there are the fixes should be made on the bug/cr branch and tested there first. This should be done with priority as the development branch may be "broken" until these changes are merged.
- Once integration testing is complete or if it is not required the bug/cr branch can be deleted locally and on github.