Git Guide: Difference between revisions

From iSchool Reference
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>


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, 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". Your branch must be named with the Jira ticket ID so that your development progress will be tracked in Jira.<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 (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.


When resuming work on a feature, retrieve your branch:
Save changes to your branch:
git checkout <feature-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.


<code>1git fetch 2git merge origin/develop</code>
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.


Do work.
<pre>
 
git fetch
Save changes to your branch:
git merge origin/main
</pre>


<code>1git commit -a -m "<message>" 2git push</code>


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


<code>1git fetch 2git merge origin/develop</code>  
<pre>
git diff


If you end up with merge conflicts, resolve them using the process below.
git commit -a -m "<message>"
git push
</pre>


When ready to push to Bitbucket 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:
=== 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:


<code>1git diff 2 3git commit -a -m "<message>" 4git push</code>
[[File:New Pull Request.png|alt=New Pull Request|161x161px]]


Log into Bitbucket and create the pull request (PR) to merge the feature branch into develop.


Creating the PR (rather than directly merging the feature branch into develop or a release branch) is important! Doing so:
Creating the PR (rather than directly merging the feature branch into main) is important! Doing so:


*provides the visual diff in Bitbucket of the lines changed, so the work can be reviewed, commented upon, and approved
*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 Bitbucket, 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
*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 Jira ticket, so it’s clear what target branches that code has ended up on
*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]]
*gives the option of "squashing" commits, so that if there are a ton of commits in a feature branch, they can all be squashed into a single commit when merged so that there are fewer commits cluttering up the commit history on the release and develop branches
*gives the option of closing the feature branch when merging the PR, so it helps prevent turds from laying around; otherwise the feature branch will remain in the repo (probably for years) until someone does house-cleaning


== 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":

create a branch


This will automatically name the branch with the issue's ID and name:

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

link branch


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:

New Pull Request


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: Linked Pull Requests

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

  1. 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
  2. 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
  3. 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
  4. Separate subject from body with a blank line
    • In the longer example: see how there's nothing on the second line?
  5. 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
  6. Capitalize the subject line
    • In the example: the first letter is capitalized in "Refactor", "Remove", "Add", and "Convert"
  7. 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
  8. 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"
  9. 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.