Git Guide: Difference between revisions
mNo edit summary |
(Update Gitflow) |
||
Line 18: | Line 18: | ||
[[File:Create a branch.png|alt=create a branch|313x313px]] | [[File:Create a branch.png|alt=create a branch|313x313px]] | ||
Line 24: | Line 25: | ||
[[File:Branch name.png|alt=branch name|322x322px]] | [[File:Branch name.png|alt=branch name|322x322px]] | ||
Then check out the branch in your local repository (where <feature-branch> is the name of the branch, e.g., "4-create-upload-page"). You'll have to fetch first so that the local repo knows that the branch exists. | |||
<pre> | |||
git fetch | |||
git checkout <feature-branch> | |||
</pre> | |||
Alternatively, you can create the branch locally, but you should still use the same naming convention. Retrieve the main branch, make sure it's up-to-date, and then create your feature branch from that, where <feature-branch> is the ID and name of the GitHub issue, such as "4-create-upload-page" | Alternatively, you can create the branch locally, but you should still use the same naming convention. Retrieve the main branch, make sure it's up-to-date (with <code>git pull</code>), and then create your feature branch from that, where <feature-branch> is the ID and name of the GitHub issue, such as "4-create-upload-page". <pre> | ||
git checkout main | git checkout main | ||
git pull | git pull | ||
git checkout -b <feature-branch> | git checkout -b <feature-branch> | ||
</pre> | </pre> | ||
Line 46: | Line 47: | ||
When resuming work on a feature, retrieve your branch: | |||
<pre>git checkout <feature-branch></pre> | |||
===Write Code=== | |||
Do work. | |||
Save changes to your branch: | |||
<pre> | |||
git add . # only needed if you've added or deleted files | |||
git commit -a -m "<message>" | |||
git push | |||
</pre> | |||
Periodically merge develop into your feature branch. The following is key: it will get whatever was added to develop since you did your last fetch from origin and try to apply your changes in <branch> on top of them, if it can. You need to resolve any conflicts on your branch; that way, we keep develop clean and safe for everyone. | Periodically merge develop into your feature branch. The following is key: it will get whatever was added to develop since you did your last fetch from origin and try to apply your changes in <branch> on top of them, if it can. You need to resolve any conflicts on your branch; that way, we keep develop clean and safe for everyone. | ||
From time to time, repeat these so your branch doesn't get behind. And be sure to ''always'' do this before creating a pull request. | |||
<pre> | |||
git fetch | |||
git merge origin/main | |||
</pre> | |||
When ready to push to GitHub and create a pull request, do a last review of all of your changes with <code>git diff</code>. Make sure you didn’t forget any experimental or debugging code, such as log statements. Then commit one last time: | |||
< | <pre> | ||
git diff | |||
git commit -a -m "<message>" | |||
git push | |||
</pre> | |||
=== Push and Review Code === | |||
Log into GitHub and create the pull request (PR) to merge the feature branch into main, by clicking the "New pull request" button on the "Branches" page: | |||
[[File:New Pull Request.png|alt=New Pull Request|161x161px]] | |||
Creating the PR (rather than directly merging the feature branch into | Creating the PR (rather than directly merging the feature branch into main) is important! Doing so: | ||
*provides the visual diff in | *provides the visual diff in GitHub of the lines changed, so the work can be reviewed, commented upon, and approved by your group | ||
*allows for a history of merged PRs in | *allows for a history of merged PRs in GitHub, so all of the work merged for the PR can be seen in one place; without that, the only option is for commit-by-commit diffs | ||
*shows the PR(s) in the | *shows the PR(s) in the GitHub project page, so it’s clear what target branches that code has ended up on: [[File:Linked Pull Requests.png|alt=Linked Pull Requests|162x162px]] | ||
== Git Commands Reference== | ==Git Commands Reference== | ||
====== <code>git clone</code>====== | ======<code>git clone</code>====== | ||
Download a copy of a repository into a new directory. | Download a copy of a repository into a new directory. | ||
Line 91: | Line 101: | ||
Switch to a different branch; specify the -b flag to create a new branch. | Switch to a different branch; specify the -b flag to create a new branch. | ||
======<code>git add .</code>====== | ======<code>git add .</code> ====== | ||
Place new files under version control. | Place new files under version control. | ||
Line 99: | Line 109: | ||
Use the -s flag for a shortened view. | Use the -s flag for a shortened view. | ||
====== <code>git commit [-am]</code>====== | ======<code>git commit [-am]</code>====== | ||
Record changes that you’ve made to the repository. | Record changes that you’ve made to the repository. | ||
Line 106: | Line 116: | ||
Use the -m flag to include a commit message; best practice is to preface your commit message with the ticket ID for whatever task you’re working on. | Use the -m flag to include a commit message; best practice is to preface your commit message with the ticket ID for whatever task you’re working on. | ||
======<code>git push</code> ====== | ======<code>git push</code>====== | ||
Update the remote repository (i.e., GitHub Classroom) with the changes that you’ve committed to your local repository. | Update the remote repository (i.e., GitHub Classroom) with the changes that you’ve committed to your local repository. | ||
======<code>git merge</code>====== | ======<code>git merge</code> ====== | ||
Join two branches together. | Join two branches together. | ||
Line 117: | Line 127: | ||
Use “git log --graph --decorate --oneline” for a concise view. | Use “git log --graph --decorate --oneline” for a concise view. | ||
======<code>git branch [-D]</code>====== | ====== <code>git branch [-D]</code>====== | ||
See the name of the branch that you’re currently on. | See the name of the branch that you’re currently on. | ||
Line 131: | Line 141: | ||
gitconfig lets you customize your Git behaves in your repositories. There are a couple different places where it can live: | gitconfig lets you customize your Git behaves in your repositories. There are a couple different places where it can live: | ||
*a file named <code>.gitconfig</code> (note the leading dot in the name) in your home directory | * a file named <code>.gitconfig</code> (note the leading dot in the name) in your home directory | ||
**e.g., in <code>C:\Users\<username>\</code> on Windows or <code>~</code> (<code>/Users/<username>/</code>) on macOS/Linux | **e.g., in <code>C:\Users\<username>\</code> on Windows or <code>~</code> (<code>/Users/<username>/</code>) on macOS/Linux | ||
**this file is global and will affect all repos on your system | ** this file is global and will affect all repos on your system | ||
*a file named <code>config</code> in the hidden .git directory in your project directory | *a file named <code>config</code> in the hidden .git directory in your project directory | ||
**this file is local and only affects the repo that contains it | ** this file is local and only affects the repo that contains it | ||
**settings in this file override the settings in the global .gitconfig | **settings in this file override the settings in the global .gitconfig | ||
Line 163: | Line 173: | ||
*it sets a bunch of aliases, so, for example, you can just type git co instead of git checkout | *it sets a bunch of aliases, so, for example, you can just type git co instead of git checkout | ||
*when pushing a branch to the remote repo, it'll default to the current branch name (which is almost always what you want) so you don't have to specify a remote name | * when pushing a branch to the remote repo, it'll default to the current branch name (which is almost always what you want) so you don't have to specify a remote name | ||
*it'll cache your password/token for 604,800 seconds (1 week) | *it'll cache your password/token for 604,800 seconds (1 week) | ||
Line 179: | Line 189: | ||
These are the general rules to keep in mind when writing a commit message: | These are the general rules to keep in mind when writing a commit message: | ||
#Start each commit message with a ticket number, such as from Jira or Azure DevOps | #Start each commit message with a ticket number, such as from Jira or Azure DevOps | ||
#*This is really important! Branches disappear, but commit messages remain forever | #*This is really important! Branches disappear, but commit messages remain forever | ||
#*Including the ticket number makes it ''a lot'' easier to figure out which task corresponds to that commit | #*Including the ticket number makes it ''a lot'' easier to figure out which task corresponds to that commit | ||
#*In the example: "PROJ-123" would correspond to a ticket in Jira or Azure DevOps | #*In the example: "PROJ-123" would correspond to a ticket in Jira or Azure DevOps | ||
#Include a pithy subject line for each commit; add a longer body for larger commits | #Include a pithy subject line for each commit; add a longer body for larger commits | ||
#*In the longer example: the subject line (the first line) is kept short, and then more details are added in the body | #*In the longer example: the subject line (the first line) is kept short, and then more details are added in the body | ||
#Use bullets (asterisks) for the body, when necessary, to clearly indicate all the work done in the commit | #Use bullets (asterisks) for the body, when necessary, to clearly indicate all the work done in the commit | ||
#*In the longer example: three bullets are used to itemize the work that was actually done to refactor the function | #* In the longer example: three bullets are used to itemize the work that was actually done to refactor the function | ||
#Separate subject from body with a blank line | #Separate subject from body with a blank line | ||
#*In the longer example: see how there's nothing on the second line? | #*In the longer example: see how there's nothing on the second line? | ||
Line 194: | Line 204: | ||
#*In the example: even with the ticket number, the total length of the subject line is 56 characters | #*In the example: even with the ticket number, the total length of the subject line is 56 characters | ||
#Capitalize the subject line | #Capitalize the subject line | ||
#*In the example: the first letter is capitalized in "Refactor", "Remove", "Add", and "Convert" | #* In the example: the first letter is capitalized in "Refactor", "Remove", "Add", and "Convert" | ||
#Do not end the subject line with a period | #Do not end the subject line with a period | ||
#*In the example: witness no periods. If the lines in the body grow longer, then it's find to separate sentences with periods or other punctuation | #*In the example: witness no periods. If the lines in the body grow longer, then it's find to separate sentences with periods or other punctuation | ||
Line 200: | Line 210: | ||
#*In the example: it's "Refactor function", not "Refactored function" or "Refactors function" | #*In the example: it's "Refactor function", not "Refactored function" or "Refactors function" | ||
#*When you're reading through commits and determining what will happen if you merge the commit into your branch, you should be able to prepend each commit message with, "If I merge this commit, it'll <commit message>". E.g., "If I merge this commit, it'll refactor function foobar() to reduce complexity" | #*When you're reading through commits and determining what will happen if you merge the commit into your branch, you should be able to prepend each commit message with, "If I merge this commit, it'll <commit message>". E.g., "If I merge this commit, it'll refactor function foobar() to reduce complexity" | ||
#Use the body to explain ''what'' and ''why'', not ''how'' | #Use the body to explain ''what'' and ''why'', not ''how'' | ||
#*E.g., don't say: "Call filter_var( $input, FILTER_SANITIZE_EMAIL )" ''Do'' say: "Sanitize email input to prevent CSS" | #*E.g., don't say: "Call filter_var( $input, FILTER_SANITIZE_EMAIL )" ''Do'' say: "Sanitize email input to prevent CSS" | ||
Most of these rules are taken from Chris Beams. [https://cbea.ms/git-commit/#seven-rules See his blog post] for a more thorough explanation of these rules. | Most of these rules are taken from Chris Beams. [https://cbea.ms/git-commit/#seven-rules See his blog post] for a more thorough explanation of these rules. |
Revision as of 12:18, 26 April 2023
Getting Started
Access Tokens
In order to access iSchool repos on GitHub Education, you’ll need to create a personal access token, which will be used like a password. Follow the steps in the GitHub documentation to create your personal access token. Make sure you save your access token someplace where you'll be able to find it again; once you leave the GitHub page where the token was created, you won't be able to see it there again.
Note that when you're prompted for a password, like when calling git push
, you actually need to enter your access token.
Installing Git
If you don’t already have Git on your computer, you’ll need to install it.
Gitflow
This suggested workflow is based on the GitHub flow.
If you're working on a larger project, especially one with multiple versions in production simultaneously, check out the branching model from Vincent Driessen.
Create and check out the branch
In the GitHub issue, click "Create a branch":
This will automatically name the branch with the issue's ID and name:
Then check out the branch in your local repository (where <feature-branch> is the name of the branch, e.g., "4-create-upload-page"). You'll have to fetch first so that the local repo knows that the branch exists.
git fetch git checkout <feature-branch>
Alternatively, you can create the branch locally, but you should still use the same naming convention. Retrieve the main branch, make sure it's up-to-date (with git pull
), and then create your feature branch from that, where <feature-branch> is the ID and name of the GitHub issue, such as "4-create-upload-page".
git checkout main git pull git checkout -b <feature-branch>
When you create a branch through the GitHub issue, it'll automatically be linked with the issue. If you create the branch locally, you'll have to link the branch manually in the GitHub issue:
When resuming work on a feature, retrieve your branch:
git checkout <feature-branch>
Write Code
Do work.
Save changes to your branch:
git add . # only needed if you've added or deleted files git commit -a -m "<message>" git push
Periodically merge develop into your feature branch. The following is key: it will get whatever was added to develop since you did your last fetch from origin and try to apply your changes in <branch> on top of them, if it can. You need to resolve any conflicts on your branch; that way, we keep develop clean and safe for everyone.
From time to time, repeat these so your branch doesn't get behind. And be sure to always do this before creating a pull request.
git fetch git merge origin/main
When ready to push to GitHub and create a pull request, do a last review of all of your changes with git diff
. Make sure you didn’t forget any experimental or debugging code, such as log statements. Then commit one last time:
git diff git commit -a -m "<message>" git push
Push and Review Code
Log into GitHub and create the pull request (PR) to merge the feature branch into main, by clicking the "New pull request" button on the "Branches" page:
Creating the PR (rather than directly merging the feature branch into main) is important! Doing so:
- provides the visual diff in GitHub of the lines changed, so the work can be reviewed, commented upon, and approved by your group
- allows for a history of merged PRs in GitHub, so all of the work merged for the PR can be seen in one place; without that, the only option is for commit-by-commit diffs
- shows the PR(s) in the GitHub project page, so it’s clear what target branches that code has ended up on:
Git Commands Reference
git clone
Download a copy of a repository into a new directory.
git checkout [-b]
Switch to a different branch; specify the -b flag to create a new branch.
git add .
Place new files under version control.
git status
Show the current state of the working tree (i.e., the files that you’re working on).
Use the -s flag for a shortened view.
git commit [-am]
Record changes that you’ve made to the repository.
Use the -a flag to automatically include files that you’ve modified or deleted; you’ll still need to use “git add .” to include any new files that you’ve created.
Use the -m flag to include a commit message; best practice is to preface your commit message with the ticket ID for whatever task you’re working on.
git push
Update the remote repository (i.e., GitHub Classroom) with the changes that you’ve committed to your local repository.
git merge
Join two branches together.
git log
See a history of commits for your current branch.
Use “git log --graph --decorate --oneline” for a concise view.
git branch [-D]
See the name of the branch that you’re currently on.
Use the -D flag to delete the branch.
git pull
Retrieve the latest commits on a branch from a remote repository.
git fetch
Get the list of available branches from a remote repository; often needed before “git pull”
gitconfig
gitconfig lets you customize your Git behaves in your repositories. There are a couple different places where it can live:
- a file named
.gitconfig
(note the leading dot in the name) in your home directory- e.g., in
C:\Users\<username>\
on Windows or~
(/Users/<username>/
) on macOS/Linux - this file is global and will affect all repos on your system
- e.g., in
- a file named
config
in the hidden .git directory in your project directory- this file is local and only affects the repo that contains it
- settings in this file override the settings in the global .gitconfig
Include the following in your gitconfig:
[user] name = First Last email = username@rit.edu [gui] [alias] st = status -s ci = commit co = checkout df = diff lol = log --graph --decorate --oneline clr = "!f() { git reset --hard && git clean -f -d; }; f" [diff] tool = vimdiff [push] default = current [color] branch = auto diff = auto status = auto [credential] helper = cache --timeout=604800
This gitconfig provides a few benefits:
- it sets a bunch of aliases, so, for example, you can just type git co instead of git checkout
- when pushing a branch to the remote repo, it'll default to the current branch name (which is almost always what you want) so you don't have to specify a remote name
- it'll cache your password/token for 604,800 seconds (1 week)
Commit Message Best Practices
Short example:
PROJ-123 Refactor function foobar() to reduce complexity
Longer example:
PROJ-123 Refactor function foobar() to reduce complexity * Remove nested loops * Add meaningful variable names * Convert nested tertiary operators to 'if' statements
These are the general rules to keep in mind when writing a commit message:
- Start each commit message with a ticket number, such as from Jira or Azure DevOps
- This is really important! Branches disappear, but commit messages remain forever
- Including the ticket number makes it a lot easier to figure out which task corresponds to that commit
- In the example: "PROJ-123" would correspond to a ticket in Jira or Azure DevOps
- Include a pithy subject line for each commit; add a longer body for larger commits
- In the longer example: the subject line (the first line) is kept short, and then more details are added in the body
- Use bullets (asterisks) for the body, when necessary, to clearly indicate all the work done in the commit
- In the longer example: three bullets are used to itemize the work that was actually done to refactor the function
- Separate subject from body with a blank line
- In the longer example: see how there's nothing on the second line?
- Limit the subject line to 80 characters and wrap the body at 80 characters
- In the example: even with the ticket number, the total length of the subject line is 56 characters
- Capitalize the subject line
- In the example: the first letter is capitalized in "Refactor", "Remove", "Add", and "Convert"
- Do not end the subject line with a period
- In the example: witness no periods. If the lines in the body grow longer, then it's find to separate sentences with periods or other punctuation
- Use the imperative mood in the subject line; i.e., write it as a present-tense command.
- In the example: it's "Refactor function", not "Refactored function" or "Refactors function"
- When you're reading through commits and determining what will happen if you merge the commit into your branch, you should be able to prepend each commit message with, "If I merge this commit, it'll <commit message>". E.g., "If I merge this commit, it'll refactor function foobar() to reduce complexity"
- Use the body to explain what and why, not how
- E.g., don't say: "Call filter_var( $input, FILTER_SANITIZE_EMAIL )" Do say: "Sanitize email input to prevent CSS"
Most of these rules are taken from Chris Beams. See his blog post for a more thorough explanation of these rules.