Difference between revisions of "Git How To"

From Dreamwidth Notes
Jump to: navigation, search
(How to check things: +git whatchanged)
(Untangling messes: Better location for interactive help)
 
(66 intermediate revisions by 8 users not shown)
Line 1: Line 1:
{{Note|text=Feel free to correct, expand, do anything which could make this better and clearer. ^_^}}
+
= Help =
  
= How to check things =
+
== How to get help with git commands ==
  
Note: to exit code views, hit the 'q' key.
+
* To get a list of most used commands:
  
* To check which local branch you're on (noted with an asterisk):
+
<syntaxhighlight lang="bash">git help</syntaxhighlight>
  
<syntaxhighlight lang="bash">git branch</syntaxhighlight>
+
* To open the Git manual:
  
* To see local and remote branches:
+
<syntaxhighlight lang="bash">man git</syntaxhighlight>
  
<syntaxhighlight lang="bash">git branch -a</syntaxhighlight>
+
* To see a summary of options for a specific command:
  
* To see the code changes you've made on the branch before you move them to the staging area:
+
<syntaxhighlight lang="bash">git COMMAND -h</syntaxhighlight>
 +
 
 +
* To open the manual page for a specific command:
 +
 
 +
<syntaxhighlight lang="bash">git help COMMAND</syntaxhighlight> or
 +
 
 +
<syntaxhighlight lang="bash">git COMMAND --help</syntaxhighlight> or
 +
 
 +
<syntaxhighlight lang="bash">man git-COMMAND</syntaxhighlight>
 +
 
 +
* To exit code views: hit the 'q' key.
 +
 
 +
 
 +
== How to use auto-completion ==
 +
 
 +
Hit the Tab key as you type to get suggestions. This works with commands and options.
 +
 
 +
: N.B. Dreamhacks have this set up automatically: see the [http://git-scm.com/book/en/Git-Basics-Tips-and-Tricks#Auto-Completion Pro Git book] on how to set it up otherwise.
 +
 
 +
 
 +
= The Basics =
 +
 
 +
* To create a branch:
 +
 
 +
<syntaxhighlight lang="bash">git branch BRANCH_NAME</syntaxhighlight>
 +
 
 +
* To switch to a branch:
 +
 
 +
<syntaxhighlight lang="bash">git checkout BRANCH_NAME</syntaxhighlight>
 +
 
 +
* To switch to the last branch you were on:
 +
 
 +
<syntaxhighlight lang="bash">git checkout -</syntaxhighlight>
 +
 
 +
* To create and switch to a branch at once:
 +
 
 +
<syntaxhighlight lang="bash">git checkout -b BRANCH_NAME</syntaxhighlight>
 +
 
 +
* To create and switch to a branch stemming from another branch:
 +
 
 +
<syntaxhighlight lang="bash">git checkout -b BRANCH_NAME OTHER_BRANCH</syntaxhighlight>
 +
 
 +
* To see unstaged code changes:
  
 
<syntaxhighlight lang="bash">git diff</syntaxhighlight>
 
<syntaxhighlight lang="bash">git diff</syntaxhighlight>
  
* To see the code changes you've made on the branch before you commit them:
+
* To move changes to the staging area:
  
<syntaxhighlight lang="bash">git diff --cached</syntaxhighlight>
+
<syntaxhighlight lang="bash">git add</syntaxhighlight>
  
* To see the list of files you've added, removed and modified on the branch before you commit them:
+
* To commit changes:
 +
 
 +
<syntaxhighlight lang="bash">git commit</syntaxhighlight>
 +
 
 +
* To add and commit changes at once:
 +
 
 +
<syntaxhighlight lang="bash">git commit -a</syntaxhighlight>
 +
 
 +
* To push changes:
 +
 
 +
<syntaxhighlight lang="bash">git push origin BRANCH_NAME</syntaxhighlight>
 +
 
 +
= Upstream Management =
 +
 
 +
== How to update to the latest code ==
 +
 
 +
* To grab the latest changes to Dreamwidth's master branch:
 +
 
 +
<syntaxhighlight lang="bash">git fetch dreamwidth
 +
git checkout master && git pull --ff-only dreamwidth master:master</syntaxhighlight>
 +
 
 +
* To push these changes to your fork on Github:
 +
 
 +
<syntaxhighlight lang="bash">git push origin master</syntaxhighlight>
 +
 
 +
Note: if you have uncommitted changes when you try to update, you'll get an error message similar to this:
 +
 
 +
mw@memewidth:~/dw/src/jbackup$ git pull dreamwidth master:master
 +
...
 +
From https://github.com/dreamwidth/dw-free
 +
    53294c1..19b8e73  master    -> master
 +
error: Your local changes to 'src/jbackup/jbackup.pl' would be overwritten by merge.  Aborting.
 +
Please, commit your changes or stash them before you can merge.
 +
 
 +
You'll want to [[#How to stash your changes|stash your changes]] first, and then try to update again.
 +
 
 +
= Staging Area Management =
 +
 
 +
== How to see staged changes ==
 +
 
 +
* To see staged code changes:
 +
 
 +
<syntaxhighlight lang="bash">git diff --cached</syntaxhighlight> or
 +
 
 +
<syntaxhighlight lang="bash">git diff --staged</syntaxhighlight>
 +
 
 +
* To see staged file changes:
  
 
<syntaxhighlight lang="bash">git status -s</syntaxhighlight>
 
<syntaxhighlight lang="bash">git status -s</syntaxhighlight>
  
* To see your last commit on a branch (before it's been merged):
+
 
 +
== How to stash your changes ==
 +
 
 +
<strong>Note:</strong> first make sure you're on the right branch using <code>checkout</code>.
 +
 
 +
* To put them away:
 +
 
 +
<syntaxhighlight lang="bash">git stash</syntaxhighlight>
 +
 
 +
* To bring them back:
 +
 
 +
<syntaxhighlight lang="bash">git stash pop</syntaxhighlight>
 +
 
 +
* To see the latest thing you've stashed:
 +
 
 +
<syntaxhighlight lang="bash">git stash show</syntaxhighlight>
 +
 
 +
 
 +
== How to undo staged changes ==
 +
 
 +
* To unstage a file:
 +
 
 +
<syntaxhighlight lang="bash">git reset HEAD FILE_PATH</syntaxhighlight>
 +
 
 +
<strong>Important:</strong> the file is still modified. It's just no longer part of your current staging area.
 +
 
 +
* To get rid of the changes after unstaging:
 +
 
 +
<syntaxhighlight lang="bash">git checkout -- FILE_PATH</syntaxhighlight>
 +
 
 +
 
 +
== How to move and delete files ==
 +
 
 +
* To move files:
 +
 
 +
<syntaxhighlight lang="bash">git mv OLD_PATH NEW_PATH</syntaxhighlight>
 +
 
 +
* To delete files:
 +
 
 +
<syntaxhighlight lang="bash">git rm FILE_PATH</syntaxhighlight>
 +
 
 +
 
 +
= Commit Management =
 +
 
 +
== How to see committed changes ==
 +
 
 +
* To see latest commits on local branches:
 +
 
 +
<syntaxhighlight lang="bash">git branch -v</syntaxhighlight>
 +
 
 +
* To see committed code changes (latest commit only):
  
 
<syntaxhighlight lang="bash">git show</syntaxhighlight>
 
<syntaxhighlight lang="bash">git show</syntaxhighlight>
  
* To see commit logs:
+
* To see past commits:
  
 
<syntaxhighlight lang="bash">git log</syntaxhighlight>
 
<syntaxhighlight lang="bash">git log</syntaxhighlight>
  
You can see them one at a time using:
+
* To see past commits one at a time:
  
 
<syntaxhighlight lang="bash">git log -1</syntaxhighlight>
 
<syntaxhighlight lang="bash">git log -1</syntaxhighlight>
<syntaxhighlight lang="bash">git log -2</syntaxhighlight>
 
  
 
and so on.
 
and so on.
  
* To see only the commits that changed a certain file:
+
* To see commits for a certain file:
  
 
<syntaxhighlight lang="bash">git whatchanged FILE</syntaxhighlight>
 
<syntaxhighlight lang="bash">git whatchanged FILE</syntaxhighlight>
  
* On github.com, you can see a graph of the branches you've pushed and the commits you've made by going to your profile page, clicking dw-free or dw-nonfree then on Network. Hit Shift and the right arrow to go to the most current part of the graph.
+
* To see what you've done locally in the last 30 days:
  
= How to stash your changes =
+
<syntaxhighlight lang="bash">git reflog</syntaxhighlight>
  
If you have work you haven't committed and don't want to yet you need to stash your work first. It's generally good practice to do this every time you have work you haven't committed.
 
  
* Make sure you're on the right branch using the <code>checkout</code> command.
+
== How to write a good commit message ==
  
* Put away your work using the <code>stash</code> command:
+
Git commit messages have a format that's rather peculiar to Git. We have a further convention of including the issue in the commit message as "Fixes #XXX" on its own line (please do include the #): this means the git-bot can close the source issue when the fix is merged. So, ideally your commit messages will look something like this:
 +
<pre>
 +
    short summary; total 50 chars or less
 +
   
 +
    After a blank line, give a long-form description of the changes.
 +
    You can write a few sentences, several paragraphs, or an essay
 +
    complete with theorems, premises, and supporting references --
 +
    whatever is needed to clearly document the change.
  
<syntaxhighlight lang="bash">git stash</syntaxhighlight>
+
    * bullet points also work
  
* And bring it back with:
+
    * describe what the code does
  
<syntaxhighlight lang="bash">git stash pop</syntaxhighlight>
+
    * if there's a tricky edge case or something weird about the code that's not immediately obvious,
 +
    go into your reasoning
  
* To see the work you've stashed, you can use:
+
    * try to start each bullet point with a verb
  
<syntaxhighlight lang="bash">git stash show</syntaxhighlight>
+
    * use the present form of the verb: "do foo" not "does foo" or "did foo"
  
 +
    * context is important. Remember that when this is viewed with git log, it will be at least
 +
    one page load away from the issue (and all comments on the issue) and at least two page loads
 +
    away from the pull request. Provide as much context as is necessary
  
= How to undo changes =
+
    * comments like "I tested x, y, z" are good but more appropriate for the pull request
 +
    (unless it's a particularly tricky edge case)
  
* If you added a file using <code>git add</code> but finally want to unstage it (i.e. remove it from the staging area before you do <code>git commit</code>), you can use the <code>reset</code> command:
+
    Fixes #XXX.
 +
</pre>
  
<syntaxhighlight lang="bash">git reset HEAD FILENAME</syntaxhighlight>
+
The first line is used as a summary by tools like <code>git log --oneline</code>; if it is too long, the output of these tools will display oddly.
  
: Note that the file is still modified; it's just no longer part of your staging area and won't be part of your commit.
+
Note that mentioning bugs in the commit message, other than the one it actually fixes, is risky as the helpful robodw-issues may assign the wrong bug to you.
  
* If you want to undo the changes you've made to a file before you commit it, you need to use <code>checkout</code>:
+
[http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html Additional suggestions on writing commit messages].
  
<syntaxhighlight lang="bash">git checkout -- FILENAME</syntaxhighlight>
+
If you are making a commit that only needs a short explanation, you can use the -m option:
  
* You can also reset everything to the last commit using <code>--hard</code>:
+
    git commit -m "This describes the change that I just made. Fixes #963"
 +
 
 +
== How to amend your last commit ==
 +
 
 +
<strong>Important:</strong> you can do this as long as nothing has been pushed.
 +
 
 +
* To update a commit with some new changes:
 +
 
 +
<syntaxhighlight lang="bash">git commit --amend</syntaxhighlight>
 +
 
 +
* To do so and reuse your last commit message:
 +
 
 +
<syntaxhighlight lang="bash">git commit --amend -C HEAD</syntaxhighlight>
 +
 
 +
 
 +
== How to undo committed changes ==
 +
 
 +
<strong>Important:</strong> you can do this as long as nothing has been pushed. Also make sure there's a commit to go back to before you do this or you'll end up in [http://gitolite.com/concepts/detached-head.html detached HEAD] state, which is as bad as it sounds.
 +
 
 +
* To reset everything to the previous commit:
  
 
<syntaxhighlight lang="bash">git reset --hard</syntaxhighlight>
 
<syntaxhighlight lang="bash">git reset --hard</syntaxhighlight>
  
* If you've already committed your work and want to go back to a clean slate, you can go one commit back using:
+
or:
  
 
<syntaxhighlight lang="bash">git reset --hard HEAD~1</syntaxhighlight>
 
<syntaxhighlight lang="bash">git reset --hard HEAD~1</syntaxhighlight>
  
 +
You can increment the number to go back to even earlier commits.
  
= How to move and delete files =
 
  
* To move files:
+
== How to push commits to the release branch ==
  
<syntaxhighlight lang="bash">git mv OLDPATH NEWPATH</syntaxhighlight>
+
Emergency fixes for issues that pop up right after a code push go into the release branch for the code push instead of the main master branch. That way, regular development of features can go on as usual while the push-related issues can be fixed and pushed live on the site ASAP.
  
* To delete files:
+
* First create a copy of the release branch:
  
<syntaxhighlight lang="bash">git rm FILEPATH</syntaxhighlight>
+
<syntaxhighlight lang="bash">git checkout -t dreamwidth/release-X.X</syntaxhighlight>
  
 +
:X-X is the number given to the release on the GitHub repo branch. Make sure it matches.
  
= How to rename and delete branches =
+
* Create a branch based on the release branch:
 +
 
 +
<syntaxhighlight lang="bash">git checkout release-X.X -b BRANCH_NAME</syntaxhighlight>
 +
 
 +
* Follow the usual steps: edit, add, commit, push.
 +
 
 +
* Select 'compare and review' then click on 'edit' to select the release branch as your base branch (you'll see all changes merged into the release branch otherwise). Send the request when you're done reviewing.
 +
 
 +
 
 +
== How to squash several commits into one ==
 +
 
 +
If, for some reason, you'd like several commits to be just one, you can squash them. This is not reversible so proceed with caution.
 +
 
 +
# Make sure everything is up-to-date.
 +
# Make sure you're on the correct branch using <code>git checkout</code>.
 +
# Load the interactive rebase interface using <syntaxhighlight lang="bash">git rebase -i master</syntaxhighlight>
 +
# The interface will show you all the successive commits on this branch, from the oldest at the top to the most recent at the bottom.
 +
 
 +
From there you have several options:
 +
* If you want to be able to edit all commit messages or merge them in some fashion, edit the work 'pick' to the word 'squash' for the ones you want to squash into the previous commit. You'll be then shown all commit messages and you'll be able to edit them, comment the lines you want to hide, etc.
 +
* If you want to edit the commit message of your master commit but discard all the other ones, use 'reword' for your master commit then 'fixup' for the other ones.
 +
* If you want to keep your master message as-is and discard the rest, use 'pick' and 'fixup' instead.
 +
 
 +
 
 +
* Note that if you had already pushed some changes to GitHub, you will need to force a push to get it updated:
 +
 
 +
<syntaxhighlight lang="bash">git push -f origin BRANCH_NAME</syntaxhighlight>
 +
 
 +
Also, [http://gitready.com/ git ready] has [http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html a nice guide to squashing commits] using the interactive rebaser (<tt>git rebase -i</tt>).
 +
 
 +
* The interactive rebaser can also do many other nifty and powerful things. You can change commit messages, edit past commits, reorder commits, or discard individual commits entirely.
 +
 
 +
 
 +
== How to copy a commit from one branch to another ==
 +
 
 +
<strong>Important:</strong> don't do this if your new branch isn't empty or if what you have will conflict with the new additions.
 +
 
 +
* Create the new branch if it doesn't exist already.
 +
 
 +
* On the old branch, find your commit hash using <code>git reflog</code>.
 +
 
 +
* Switch to the new branch then use:
 +
 
 +
<syntaxhighlight lang="bash">git cherry-pick HASH</syntaxhighlight>
 +
 
 +
== How to add/commit only part of a file ==
 +
 
 +
There are times when you want to commit only ''some'' of the changes you've made to a file.  Maybe you've fixed one thing, and are in the midst of fixing a second thing somewhere else in that file when you decide you want to commit the first change. 
 +
 
 +
You don't have to back out the work you've done on the second fix in order to commit the first change by itself.  Use the interactive option of <tt>git add</tt>:
 +
 
 +
<syntaxhighlight lang="bash">
 +
# consider all changed files for addition
 +
git add -i
 +
# consider only the files specified
 +
git add -i FILE [FILE2 FILE3 ...]
 +
</syntaxhighlight>
 +
 
 +
You'll be shown the current staging status of the file(s), and how many lines in each of them are staged (added) or unstaged (not added yet).
 +
 
 +
    twilight:~/temp rick$ git add -i
 +
              staged    unstaged path
 +
      1:    unchanged        +9/-8 bar.pl
 +
      2:    unchanged        +2/-1 foo.pl
 +
      3:    unchanged        +2/-0 index.html
 +
   
 +
    *** Commands ***
 +
      1: [s]tatus    2: [u]pdate    3: [r]evert    4: [a]dd untracked
 +
      5: [p]atch      6: [d]iff      7: [q]uit      8: [h]elp
 +
    What now>
 +
 
 +
There are a lot of commands, but you really only need very few of them.  Too, there's help available in each menu -- you can enter ? at any prompt for help, in addition to any visible help options.
 +
 
 +
* 1: shows you the current staging status, just like when <tt>git add -i</tt> started.
 +
* 2: stage (add) whole files
 +
* 3: unstage (un-add) whole files
 +
* 4: add a currently-untracked file
 +
* 5: stage individual chunks in a file bit-by-bit 
 +
* 6: show the diff between what's been staged so far & the previous commit
 +
 
 +
Number 5 (patch) is the biggest winner of all these, and usually why you're running the command at all.  Select 5 and you'll be presented with a menu like this one:
 +
 
 +
              staged    unstaged path
 +
      1:    unchanged        +9/-8 [b]ar.pl
 +
      2:    unchanged        +2/-1 [f]oo.pl
 +
      3:    unchanged        +2/-0 [i]ndex.html
 +
    Patch update>>
 +
 
 +
Pick the file or files you want to part-stage by entering their number(s), then hitting enter.  When you're done picking files, hit enter once more at the empty <tt>Patch Update&gt;&gt;</tt> prompt.  The program will show you every change in the files you've selected, one at a time, and ask you if you want to add it, eg:
 +
 
 +
    diff --git a/index.html b/index.html
 +
    index 32870ee..416e0bd 100644
 +
    --- a/index.html
 +
    +++ b/index.html
 +
    @@ -8,6 +8,7 @@
 +
   
 +
   
 +
        <link rel="stylesheet" type="text/css" href="./css/base.css" />
 +
    +    <link rel="stylesheet" type="text/css" href="./css/frontpage.css" />
 +
       
 +
        <title>Welcome!</title>
 +
      </head>
 +
    Stage this hunk [y/n/a/d/e/?]?
 +
 
 +
Hit y to add this change, n to not add it for now.  There are many more options, like splitting a change in two or adding every change left in the file -- you can hit ? to see those.
 +
 
 +
When you're done, you're taken back to the main menu.  If you're finished, hit 7 to quit.  If you want, you can then review everything you've added by giving the command
 +
 
 +
<syntaxhighlight lang="bash">git diff --cached</syntaxhighlight>
 +
 
 +
 
 +
= Branch Management =
 +
 
 +
== How to see branches ==
 +
 
 +
* To check which local branch you're on (noted with an asterisk):
 +
 
 +
<syntaxhighlight lang="bash">git branch</syntaxhighlight>
 +
 
 +
* To see local and remote branches (including deleted ones):
 +
 
 +
<syntaxhighlight lang="bash">git branch -a</syntaxhighlight>
 +
 
 +
* To see branches on a graph: go to your profile page on github.com, click dw-free or dw-nonfree then Graphs/Network. Hit Shift and the right arrow to go to the most current part of the graph.
 +
 
 +
* To see merged branches:
 +
 
 +
<syntaxhighlight lang="bash">git branch --merged</syntaxhighlight>
 +
 
 +
* To see unmerged branches:
 +
 
 +
<syntaxhighlight lang="bash">git branch --no-merged</syntaxhighlight>
 +
 
 +
<strong>Note:</strong> you can also see merged and unmerged branches on GitHub. On your profile, click on the Repositories tab, select yours then click on Branches (and view merged branches).
 +
 
 +
* To see where local branches stem off, which branch is also on GitHub and what is the latest commit on each branch and its abbreviated hash ref:
 +
 
 +
<syntaxhighlight lang="bash">git log --all --abbrev-commit --decorate --oneline  --simplify-by-decoration</syntaxhighlight>
 +
 
 +
Note that [https://www.kernel.org/pub/software/scm/git/docs/git-log.html git log has many options] letting you do wonderful things which might help you better.
 +
 
 +
== How to create a new branch for feature development / bugfixes ==
 +
 
 +
All code changes should happen in a branch, whether it's a huge long-running feature or a tiny bugfix.
 +
 
 +
Before you create your branch, make sure your copy of master is [[#How to update to the latest code|up-to-date]] (it will save you headaches later). Then create your branch:
 +
 
 +
<syntaxhighlight lang="bash">git checkout master -b BRANCH_NAME-bug-XXX</syntaxhighlight>
 +
 
 +
Choose a descriptive branch name you can keep track of--in this example, it's the bug number being worked on, plus a couple of keywords so you're not relying solely on memorizing bug numbers. Remember you can use [[#How to use auto-completion|auto-completion]] to make it easier to switch to your branch later.
 +
 
 +
In addition, you can also set up a script to [[#How to automatically insert the issue number into your commit message|automatically insert the issue number into your commit message]] based on your branch name.
 +
 
 +
 
 +
== How to rename and delete branches ==
  
 
* To rename a local branch:
 
* To rename a local branch:
  
<syntaxhighlight lang="bash">git branch -m OLDNAME NEWNAME</syntaxhighlight>
+
<syntaxhighlight lang="bash">git branch -m OLD_NAME NEW_NAME</syntaxhighlight>
  
: N.B. If you had already pushed some changes to GitHub, this will create a new identical branch there. You will need to delete the old one using the method described below.
+
<strong>Important:</strong> if you had already pushed some changes to GitHub, this will create a new identical branch there. You will need to delete the old one using the method described below.
  
* To delete a local branch you created by mistake or a branch which has been merged into develop (you must update your code for the system to detect the merge), use:
+
* To delete a local branch or a merged branch:
  
<syntaxhighlight lang="bash">git branch -d BRANCHNAME</syntaxhighlight>
+
<syntaxhighlight lang="bash">git branch -d BRANCH_NAME</syntaxhighlight>
  
* To delete an unmerged branch, use this instead:
+
<strong>Important:</strong> the merge will only be detected if you've updated your code. Otherwise, you'll get an error saying the branch isn't fully merged.
  
<syntaxhighlight lang="bash">git branch -D BRANCHNAME</syntaxhighlight>
+
* To delete an unmerged branch:
  
* To delete the remote branch on GitHub:
+
<syntaxhighlight lang="bash">git branch -D BRANCH_NAME</syntaxhighlight>
  
<syntaxhighlight lang="bash">git push origin :BRANCHNAME</syntaxhighlight>
+
* To delete a branch on GitHub:
  
: You can also do this directly on GitHub one your pull request has been merged into develop. Just click on the pull request (from the Activity list on your profile for example), scroll down and it'll ask if you want to delete the branch.
+
<syntaxhighlight lang="bash">git push origin :BRANCH_NAME</syntaxhighlight>
  
 +
<strong>Note:</strong> you can also do this directly on GitHub once your branch has been merged into master. Just click on the pull request (from the Activity list on your profile for example), scroll down and it'll ask if you want to delete the branch.
  
= How to update your branch =
 
  
* If, for some reason, you'd like to update your branch so it has all the new code which has been added to develop since then, you can do so with <code>rebase</code>. However, this will only work smoothly if you have nothing on your branch of if what you have has been committed and won't conflict with the new additions. If that's the case then run:
+
== How to pull the latest changes from master into your branch ==
  
<syntaxhighlight lang="bash">git checkout BRANCHNAME
+
<strong>Important:</strong> don't do this if your branch isn't empty or if what you have will conflict with the new additions.
git rebase develop</syntaxhighlight>
+
  
Ta-da! All new!
+
If it's been a while since you've worked on your bug, you may want to or need to bring your branch up to date with any changes that have happened in <tt>master</tt> since you initially forked your branch.
  
* If you had already pushed some changes to GitHub, you will need to force a push to get it updated:
+
* To update your branch so it has all the new code which has been added to master since you created it:
  
<syntaxhighlight lang="bash">git push -f origin BRANCHNAME</syntaxhighlight>
+
<syntaxhighlight lang="bash">git checkout BRANCH_NAME
 +
git pull --rebase --ff-only dreamwidth master</syntaxhighlight>  
  
 +
* You can also do this with other branches such as the current release branch by checking out the release branch then pulling from <code>release-X.X</code> instead of <code>master</code>.
  
= How to squash several commits into one =
+
<tt>pull --rebase</tt> incorporates any new changes from master into your branch, and it also reorganizes your changes so that changes in your branch appear to start from ''current'' master, instead of where master was when you initially started your branch.  (Neat!)  This can make it much easier to merge your branch into Dreamwidth's main master branch.
  
If, for some reason, you'd like several commits to be just one, you can squash them. This is not reversible so proceed with caution.
+
* If you had already pushed your branch to GitHub, you will need to force push your changes:
  
# Make sure everything is up-to-date.
+
<syntaxhighlight lang="bash">git push -f origin BRANCH_NAME</syntaxhighlight>
# Make sure you're on the correct bug branch using <code>git checkout</code>.
+
# Use <code>git log</code> or <code>git log -n</code> to check the ID of the commits you want to squash. It might come in handy later.
+
# Load the interactive rebase interface using <syntaxhighlight lang="bash">git rebase -i develop</syntaxhighlight>
+
# The interface will show you all the successive commits on this branch, from the oldest at the top to the most recent at the bottom.
+
# Edit the work 'pick' to the word 'squash' for the ones you want to squash into the previous commit. This is where the commit IDs can be useful as the commit message is shortened and it may not be easy to say which is what. Each line shows the first seven characters of the commit ID.
+
# When you're done hit Ctrl+X then type Y and Enter.
+
# You'll be then shown the commit messages if you want to edit or remove them. When you're done hit Ctrl+X, Y and Enter again.
+
# Ta-da!
+
# Note that if you had already pushed some changes to GitHub, you will need to force a push to get it updated:
+
  
<syntaxhighlight lang="bash">git push -f origin BRANCHNAME</syntaxhighlight>
 
  
 +
== How to change where your branch stems off ==
  
= How to create custom keywords for your most-used commands =
+
<strong>Important:</strong> depending on where you put it what you have may conflict with what's already there. You'll then have to resolve conflicts manually or abort the rebase.
  
* Tired of (mis)typing the same things over and over? You can create keywords for them. Open config in ~/dw/.git. Add this at the bottom and edit as desired:
+
* To change the point of origin of a branch:
 +
 
 +
<syntaxhighlight lang="bash">git rebase --onto NEW_BASE OLD_BASE BRANCH_NAME</syntaxhighlight>
 +
 
 +
For example, if you want to move something from master to a release branch you'd use:
 +
 
 +
<syntaxhighlight lang="bash">git rebase --onto release-X.X master BRANCH_NAME</syntaxhighlight>
 +
 
 +
== Resolving conflicts manually ==
 +
[[Git_How_To/Conflict_resolution|Rough chat log from #dreamwidth]]
 +
 
 +
= Pull Request Management =
 +
 
 +
== How to submit a pull request ==
 +
 
 +
Go to your version of the repository (dw-free or dw-nonfree) that you want to send upstream.  By default they should be at:
 +
 
 +
* https://github.com/USERNAME/dw-free
 +
* https://github.com/USERNAME/dw-nonfree
 +
 
 +
These repositories are separate, so if you have made changes to both of them, you will have to submit pull requests for both of them.
 +
 
 +
Find your branch in the drop-down menu then click on Compare and Pull Request right above it. Check your request one last time then click on Send Pull Request. Make sure you've included the sentence "Fixes #XXX", where #XXX is the issue number in your commit message - Github does some magic behind the scenes which makes record-keeping/issue-tracking much easier!
 +
 
 +
All pull requests are reviewed by a senior Dreamwidth developer before committing (or returning for further work).
 +
 
 +
 
 +
== How to update a pull request after it's been reviewed  ==
 +
Pull requests all go through review, and it is common to have multiple passes with suggestions to improve the functionality, tweak the interface, or improve the code. This means that you'll need to go back to the relevant branch and add new commits.
 +
 
 +
* If you're not on the right branch, switch to the branch you want to work on
 +
 
 +
* Make requested changes, commit
 +
 
 +
* Push your changes live (the pull request will automatically update with your new commits)
 +
 
 +
* Comment on the pull request so that the reviewer is aware that something has changed. Reviewers aren't notified of new commits, but are notified of new comments.
 +
 
 +
 
 +
== How to modify existing commits in a pull request ==
 +
 
 +
Sometimes the reviewer requests cleanup of existing commits -- situations where that may happen are if there are a lot of cleanup commits ("removed debug log"), or if there are suggested improvements to the commit message (referring to the issue number, clarity of message, etc).
 +
 
 +
In that case, follow the instructions under [[#How to squash several commits into one]], which describes how to merge multiple commits together, and how to reword the messages of existing commits.
 +
 
 +
 
 +
= Git Configuration =
 +
 
 +
== How to create custom keywords for your most-used commands ==
 +
 
 +
* Tired of (mis)typing the same things over and over? You can create keywords for them. Open .gitconfig in your root folder. Add this at the bottom and edit as desired:
  
 
<syntaxhighlight lang="bash">[alias]
 
<syntaxhighlight lang="bash">[alias]
Line 164: Line 529:
 
* You can then use your keyword instead of typing the full command (e.g. <code>git c</code> instead of <code>git checkout -b</code>).
 
* You can then use your keyword instead of typing the full command (e.g. <code>git c</code> instead of <code>git checkout -b</code>).
  
 +
 +
== How to list your custom keywords ==
 +
 +
Because who doesn't forget them? :)
 +
 +
<syntaxhighlight lang="bash">git config --get-regexp alias</syntaxhighlight>
 +
 +
 +
== How to configure git ==
 +
 +
See [[Git settings]] for some of the most useful settings.
 +
 +
 +
== How to create a default commit message ==
 +
 +
Easy peasy! In your root folder, create a file called <code>.gitmessage.txt</code> with whatever default message you wanna use then edit .gitconfig to use it:
 +
 +
<syntaxhighlight lang="bash">git config --global commit.template $HOME/.gitmessage.txt</syntaxhighlight>
 +
 +
 +
== How to automatically insert the issue number into your commit message==
 +
 +
Important! This will only work if 'bug-XXX' where XXX is the issue number is in your branch name. This is meant as a way not to have to type it or paste it *again* in your commit messages.
 +
 +
Go to ~/dw/.git/hooks/ and create a filed called <code>prepare-commit-msg</code>. [https://gist.github.com/afuna/ae9386b122d6a490eaf9 Paste this gist] made by the brilliant <dwuser>fu</dwuser> and save. Finally make it executable by running:
 +
 +
<syntaxhighlight lang="bash">chmod u+x ~/dw/.git/hooks/prepare-commit-msg</syntaxhighlight>
 +
 +
: N.B. This can be used in conjunction with the default commit message mentioned in the previous section.
 +
 +
 +
= Troubleshooting =
 +
== Why am I getting 'Permission denied'? ==
 +
 +
Before running any of the <tt>git</tt> commands on this page, you will need to ensure you are somewhere within the <tt>$LJHOME</tt> directory tree. On Dreamhacks, if you are not within this directory tree, you may receive errors like this:
 +
 +
    fatal: Unable to create '/dreamhack/.git/refs/heads/dj.lock': Permission denied
 +
 +
This occurs because the Dreamhack machine uses its own git repository for its code too, and Git is thinking that you wanted to use this repository instead of your own personal repository. To fix this, simply change to the <tt>$LJHOME</tt> directory:
 +
 +
<syntaxhighlight lang="bash">cd $LJHOME</syntaxhighlight>
 +
 +
The commands should now work without issue.
 +
 +
== Untangling messes ==
 +
If your account or branch is in some kind of unfortunate state that you do not know how to recover from:
 +
 +
* try not to panic
 +
* try not to blame yourself -- this is a very common situation, especially while first getting used to git.
 +
* feel free to ask for help, particularly in <dwcomm>dw_dev_training</dwcomm> or, for real-time support, in [[Chat#Channels|the Development Discord channel]]; it can help to come prepared with a pastebin link of what's going on in your account, and explain what you're trying to do.
 +
 +
= References =
 +
 +
[http://stackoverflow.com/ Stack Overflow]: one of the best places to find out if there's a command for what you wanna do.
 +
 +
[http://git-scm.com/docs Command Index]
  
 
[[Category:Development]]
 
[[Category:Development]]
 
[[Category:Getting Started]]
 
[[Category:Getting Started]]
 
[[Category:Git]]
 
[[Category:Git]]

Latest revision as of 14:11, 12 July 2022

Help

How to get help with git commands

  • To get a list of most used commands:
git help
  • To open the Git manual:
man git
  • To see a summary of options for a specific command:
git COMMAND -h
  • To open the manual page for a specific command:
git help COMMAND
or
git COMMAND --help
or
man git-COMMAND
  • To exit code views: hit the 'q' key.


How to use auto-completion

Hit the Tab key as you type to get suggestions. This works with commands and options.

N.B. Dreamhacks have this set up automatically: see the Pro Git book on how to set it up otherwise.


The Basics

  • To create a branch:
git branch BRANCH_NAME
  • To switch to a branch:
git checkout BRANCH_NAME
  • To switch to the last branch you were on:
git checkout -
  • To create and switch to a branch at once:
git checkout -b BRANCH_NAME
  • To create and switch to a branch stemming from another branch:
git checkout -b BRANCH_NAME OTHER_BRANCH
  • To see unstaged code changes:
git diff
  • To move changes to the staging area:
git add
  • To commit changes:
git commit
  • To add and commit changes at once:
git commit -a
  • To push changes:
git push origin BRANCH_NAME

Upstream Management

How to update to the latest code

  • To grab the latest changes to Dreamwidth's master branch:
git fetch dreamwidth
git checkout master && git pull --ff-only dreamwidth master:master
  • To push these changes to your fork on Github:
git push origin master

Note: if you have uncommitted changes when you try to update, you'll get an error message similar to this:

mw@memewidth:~/dw/src/jbackup$ git pull dreamwidth master:master
...
From https://github.com/dreamwidth/dw-free
   53294c1..19b8e73  master    -> master
error: Your local changes to 'src/jbackup/jbackup.pl' would be overwritten by merge.  Aborting.
Please, commit your changes or stash them before you can merge.

You'll want to stash your changes first, and then try to update again.

Staging Area Management

How to see staged changes

  • To see staged code changes:
git diff --cached
or
git diff --staged
  • To see staged file changes:
git status -s


How to stash your changes

Note: first make sure you're on the right branch using checkout.

  • To put them away:
git stash
  • To bring them back:
git stash pop
  • To see the latest thing you've stashed:
git stash show


How to undo staged changes

  • To unstage a file:
git reset HEAD FILE_PATH

Important: the file is still modified. It's just no longer part of your current staging area.

  • To get rid of the changes after unstaging:
git checkout -- FILE_PATH


How to move and delete files

  • To move files:
git mv OLD_PATH NEW_PATH
  • To delete files:
git rm FILE_PATH


Commit Management

How to see committed changes

  • To see latest commits on local branches:
git branch -v
  • To see committed code changes (latest commit only):
git show
  • To see past commits:
git log
  • To see past commits one at a time:
git log -1

and so on.

  • To see commits for a certain file:
git whatchanged FILE
  • To see what you've done locally in the last 30 days:
git reflog


How to write a good commit message

Git commit messages have a format that's rather peculiar to Git. We have a further convention of including the issue in the commit message as "Fixes #XXX" on its own line (please do include the #): this means the git-bot can close the source issue when the fix is merged. So, ideally your commit messages will look something like this:

    short summary; total 50 chars or less
    
    After a blank line, give a long-form description of the changes.
    You can write a few sentences, several paragraphs, or an essay
    complete with theorems, premises, and supporting references --
    whatever is needed to clearly document the change.

    * bullet points also work

    * describe what the code does

    * if there's a tricky edge case or something weird about the code that's not immediately obvious,
    go into your reasoning

    * try to start each bullet point with a verb

    * use the present form of the verb: "do foo" not "does foo" or "did foo"

    * context is important. Remember that when this is viewed with git log, it will be at least
    one page load away from the issue (and all comments on the issue) and at least two page loads
    away from the pull request. Provide as much context as is necessary

    * comments like "I tested x, y, z" are good but more appropriate for the pull request
    (unless it's a particularly tricky edge case)

    Fixes #XXX.

The first line is used as a summary by tools like git log --oneline; if it is too long, the output of these tools will display oddly.

Note that mentioning bugs in the commit message, other than the one it actually fixes, is risky as the helpful robodw-issues may assign the wrong bug to you.

Additional suggestions on writing commit messages.

If you are making a commit that only needs a short explanation, you can use the -m option:

   git commit -m "This describes the change that I just made. Fixes #963"

How to amend your last commit

Important: you can do this as long as nothing has been pushed.

  • To update a commit with some new changes:
git commit --amend
  • To do so and reuse your last commit message:
git commit --amend -C HEAD


How to undo committed changes

Important: you can do this as long as nothing has been pushed. Also make sure there's a commit to go back to before you do this or you'll end up in detached HEAD state, which is as bad as it sounds.

  • To reset everything to the previous commit:
git reset --hard

or:

git reset --hard HEAD~1

You can increment the number to go back to even earlier commits.


How to push commits to the release branch

Emergency fixes for issues that pop up right after a code push go into the release branch for the code push instead of the main master branch. That way, regular development of features can go on as usual while the push-related issues can be fixed and pushed live on the site ASAP.

  • First create a copy of the release branch:
git checkout -t dreamwidth/release-X.X
X-X is the number given to the release on the GitHub repo branch. Make sure it matches.
  • Create a branch based on the release branch:
git checkout release-X.X -b BRANCH_NAME
  • Follow the usual steps: edit, add, commit, push.
  • Select 'compare and review' then click on 'edit' to select the release branch as your base branch (you'll see all changes merged into the release branch otherwise). Send the request when you're done reviewing.


How to squash several commits into one

If, for some reason, you'd like several commits to be just one, you can squash them. This is not reversible so proceed with caution.

  1. Make sure everything is up-to-date.
  2. Make sure you're on the correct branch using git checkout.
  3. Load the interactive rebase interface using
    git rebase -i master
  4. The interface will show you all the successive commits on this branch, from the oldest at the top to the most recent at the bottom.

From there you have several options:

  • If you want to be able to edit all commit messages or merge them in some fashion, edit the work 'pick' to the word 'squash' for the ones you want to squash into the previous commit. You'll be then shown all commit messages and you'll be able to edit them, comment the lines you want to hide, etc.
  • If you want to edit the commit message of your master commit but discard all the other ones, use 'reword' for your master commit then 'fixup' for the other ones.
  • If you want to keep your master message as-is and discard the rest, use 'pick' and 'fixup' instead.


  • Note that if you had already pushed some changes to GitHub, you will need to force a push to get it updated:
git push -f origin BRANCH_NAME

Also, git ready has a nice guide to squashing commits using the interactive rebaser (git rebase -i).

  • The interactive rebaser can also do many other nifty and powerful things. You can change commit messages, edit past commits, reorder commits, or discard individual commits entirely.


How to copy a commit from one branch to another

Important: don't do this if your new branch isn't empty or if what you have will conflict with the new additions.

  • Create the new branch if it doesn't exist already.
  • On the old branch, find your commit hash using git reflog.
  • Switch to the new branch then use:
git cherry-pick HASH

How to add/commit only part of a file

There are times when you want to commit only some of the changes you've made to a file. Maybe you've fixed one thing, and are in the midst of fixing a second thing somewhere else in that file when you decide you want to commit the first change.

You don't have to back out the work you've done on the second fix in order to commit the first change by itself. Use the interactive option of git add:

# consider all changed files for addition 
git add -i 
# consider only the files specified 
git add -i FILE [FILE2 FILE3 ...]

You'll be shown the current staging status of the file(s), and how many lines in each of them are staged (added) or unstaged (not added yet).

   twilight:~/temp rick$ git add -i
              staged     unstaged path
     1:    unchanged        +9/-8 bar.pl
     2:    unchanged        +2/-1 foo.pl
     3:    unchanged        +2/-0 index.html
   
   *** Commands ***
     1: [s]tatus     2: [u]pdate     3: [r]evert     4: [a]dd untracked
     5: [p]atch      6: [d]iff       7: [q]uit       8: [h]elp
   What now> 

There are a lot of commands, but you really only need very few of them. Too, there's help available in each menu -- you can enter ? at any prompt for help, in addition to any visible help options.

  • 1: shows you the current staging status, just like when git add -i started.
  • 2: stage (add) whole files
  • 3: unstage (un-add) whole files
  • 4: add a currently-untracked file
  • 5: stage individual chunks in a file bit-by-bit
  • 6: show the diff between what's been staged so far & the previous commit

Number 5 (patch) is the biggest winner of all these, and usually why you're running the command at all. Select 5 and you'll be presented with a menu like this one:

              staged     unstaged path
     1:    unchanged        +9/-8 [b]ar.pl
     2:    unchanged        +2/-1 [f]oo.pl
     3:    unchanged        +2/-0 [i]ndex.html
   Patch update>> 

Pick the file or files you want to part-stage by entering their number(s), then hitting enter. When you're done picking files, hit enter once more at the empty Patch Update>> prompt. The program will show you every change in the files you've selected, one at a time, and ask you if you want to add it, eg:

   diff --git a/index.html b/index.html
   index 32870ee..416e0bd 100644
   --- a/index.html
   +++ b/index.html
   @@ -8,6 +8,7 @@
    
    
        <link rel="stylesheet" type="text/css" href="./css/base.css" />
   +    <link rel="stylesheet" type="text/css" href="./css/frontpage.css" />
        
        <title>Welcome!</title>
      </head>
   Stage this hunk [y/n/a/d/e/?]? 

Hit y to add this change, n to not add it for now. There are many more options, like splitting a change in two or adding every change left in the file -- you can hit ? to see those.

When you're done, you're taken back to the main menu. If you're finished, hit 7 to quit. If you want, you can then review everything you've added by giving the command

git diff --cached


Branch Management

How to see branches

  • To check which local branch you're on (noted with an asterisk):
git branch
  • To see local and remote branches (including deleted ones):
git branch -a
  • To see branches on a graph: go to your profile page on github.com, click dw-free or dw-nonfree then Graphs/Network. Hit Shift and the right arrow to go to the most current part of the graph.
  • To see merged branches:
git branch --merged
  • To see unmerged branches:
git branch --no-merged

Note: you can also see merged and unmerged branches on GitHub. On your profile, click on the Repositories tab, select yours then click on Branches (and view merged branches).

  • To see where local branches stem off, which branch is also on GitHub and what is the latest commit on each branch and its abbreviated hash ref:
git log --all --abbrev-commit --decorate --oneline  --simplify-by-decoration

Note that git log has many options letting you do wonderful things which might help you better.

How to create a new branch for feature development / bugfixes

All code changes should happen in a branch, whether it's a huge long-running feature or a tiny bugfix.

Before you create your branch, make sure your copy of master is up-to-date (it will save you headaches later). Then create your branch:

git checkout master -b BRANCH_NAME-bug-XXX

Choose a descriptive branch name you can keep track of--in this example, it's the bug number being worked on, plus a couple of keywords so you're not relying solely on memorizing bug numbers. Remember you can use auto-completion to make it easier to switch to your branch later.

In addition, you can also set up a script to automatically insert the issue number into your commit message based on your branch name.


How to rename and delete branches

  • To rename a local branch:
git branch -m OLD_NAME NEW_NAME

Important: if you had already pushed some changes to GitHub, this will create a new identical branch there. You will need to delete the old one using the method described below.

  • To delete a local branch or a merged branch:
git branch -d BRANCH_NAME

Important: the merge will only be detected if you've updated your code. Otherwise, you'll get an error saying the branch isn't fully merged.

  • To delete an unmerged branch:
git branch -D BRANCH_NAME
  • To delete a branch on GitHub:
git push origin :BRANCH_NAME

Note: you can also do this directly on GitHub once your branch has been merged into master. Just click on the pull request (from the Activity list on your profile for example), scroll down and it'll ask if you want to delete the branch.


How to pull the latest changes from master into your branch

Important: don't do this if your branch isn't empty or if what you have will conflict with the new additions.

If it's been a while since you've worked on your bug, you may want to or need to bring your branch up to date with any changes that have happened in master since you initially forked your branch.

  • To update your branch so it has all the new code which has been added to master since you created it:
git checkout BRANCH_NAME
git pull --rebase --ff-only dreamwidth master
  • You can also do this with other branches such as the current release branch by checking out the release branch then pulling from release-X.X instead of master.

pull --rebase incorporates any new changes from master into your branch, and it also reorganizes your changes so that changes in your branch appear to start from current master, instead of where master was when you initially started your branch. (Neat!) This can make it much easier to merge your branch into Dreamwidth's main master branch.

  • If you had already pushed your branch to GitHub, you will need to force push your changes:
git push -f origin BRANCH_NAME


How to change where your branch stems off

Important: depending on where you put it what you have may conflict with what's already there. You'll then have to resolve conflicts manually or abort the rebase.

  • To change the point of origin of a branch:
git rebase --onto NEW_BASE OLD_BASE BRANCH_NAME

For example, if you want to move something from master to a release branch you'd use:

git rebase --onto release-X.X master BRANCH_NAME

Resolving conflicts manually

Rough chat log from #dreamwidth

Pull Request Management

How to submit a pull request

Go to your version of the repository (dw-free or dw-nonfree) that you want to send upstream. By default they should be at:

These repositories are separate, so if you have made changes to both of them, you will have to submit pull requests for both of them.

Find your branch in the drop-down menu then click on Compare and Pull Request right above it. Check your request one last time then click on Send Pull Request. Make sure you've included the sentence "Fixes #XXX", where #XXX is the issue number in your commit message - Github does some magic behind the scenes which makes record-keeping/issue-tracking much easier!

All pull requests are reviewed by a senior Dreamwidth developer before committing (or returning for further work).


How to update a pull request after it's been reviewed

Pull requests all go through review, and it is common to have multiple passes with suggestions to improve the functionality, tweak the interface, or improve the code. This means that you'll need to go back to the relevant branch and add new commits.

  • If you're not on the right branch, switch to the branch you want to work on
  • Make requested changes, commit
  • Push your changes live (the pull request will automatically update with your new commits)
  • Comment on the pull request so that the reviewer is aware that something has changed. Reviewers aren't notified of new commits, but are notified of new comments.


How to modify existing commits in a pull request

Sometimes the reviewer requests cleanup of existing commits -- situations where that may happen are if there are a lot of cleanup commits ("removed debug log"), or if there are suggested improvements to the commit message (referring to the issue number, clarity of message, etc).

In that case, follow the instructions under #How to squash several commits into one, which describes how to merge multiple commits together, and how to reword the messages of existing commits.


Git Configuration

How to create custom keywords for your most-used commands

  • Tired of (mis)typing the same things over and over? You can create keywords for them. Open .gitconfig in your root folder. Add this at the bottom and edit as desired:
[alias]
	KEYWORD1= COMMAND1
	KEYWORD2= COMMAND2
Warning! Make sure the keyword you're using isn't already a git command.
  • You can then use your keyword instead of typing the full command (e.g. git c instead of git checkout -b).


How to list your custom keywords

Because who doesn't forget them? :)

git config --get-regexp alias


How to configure git

See Git settings for some of the most useful settings.


How to create a default commit message

Easy peasy! In your root folder, create a file called .gitmessage.txt with whatever default message you wanna use then edit .gitconfig to use it:

git config --global commit.template $HOME/.gitmessage.txt


How to automatically insert the issue number into your commit message

Important! This will only work if 'bug-XXX' where XXX is the issue number is in your branch name. This is meant as a way not to have to type it or paste it *again* in your commit messages.

Go to ~/dw/.git/hooks/ and create a filed called prepare-commit-msg. Paste this gist made by the brilliant [info]fu and save. Finally make it executable by running:

chmod u+x ~/dw/.git/hooks/prepare-commit-msg
N.B. This can be used in conjunction with the default commit message mentioned in the previous section.


Troubleshooting

Why am I getting 'Permission denied'?

Before running any of the git commands on this page, you will need to ensure you are somewhere within the $LJHOME directory tree. On Dreamhacks, if you are not within this directory tree, you may receive errors like this:

   fatal: Unable to create '/dreamhack/.git/refs/heads/dj.lock': Permission denied

This occurs because the Dreamhack machine uses its own git repository for its code too, and Git is thinking that you wanted to use this repository instead of your own personal repository. To fix this, simply change to the $LJHOME directory:

cd $LJHOME

The commands should now work without issue.

Untangling messes

If your account or branch is in some kind of unfortunate state that you do not know how to recover from:

  • try not to panic
  • try not to blame yourself -- this is a very common situation, especially while first getting used to git.
  • feel free to ask for help, particularly in [info]dw_dev_training or, for real-time support, in the Development Discord channel; it can help to come prepared with a pastebin link of what's going on in your account, and explain what you're trying to do.

References

Stack Overflow: one of the best places to find out if there's a command for what you wanna do.

Command Index