# Git ## Common commands - Start a new git repository: `git init` **OR** `gi` - Clone a git repository from an upstream url: `git clone ` - Add files to commit: `git add ` **OR** `ga ` - Commit those files to the repository: `git commit -m ` **OR** `gc ` - Undo the last commit and keep the changes: `gr` **OR** `git reset HEAD~` - Undo the last soft git reset: `git reset 'HEAD@{1}'` - Undo the last commit and delete changes: `grr` - Also known as a "hard" git reset - Update your local repository with a remote repository: `git pull ` - Most of the time you'll be using `origin master` to pull from your remote repository and `upstream master` to pull from the upstream repository - This is the equivalent of clicking "accept pull request" on GitHub - Show the status of the local repository: `git status` **OR** `gs` **OR** `git s` - Push changes from your local repository to a remote repository: `git push ` **OR** `git push` **OR** `gp` - The most common use is `git push origin master`, which is usually the default for `git push` - Show the difference between the staging area and the working tree: `git diff` **OR** `gd` - Show the changes that you added but haven't committed yet: `git diff --staged` **OR** `gd --staged` **OR** `gds` - Show a log of all the commits: `git log` (full log) **OR** `git lg` (commits only, easier to read) - Edit the last commit message: `git commit --amend` - To add new file changes to a previous commit, simply `git add` those files before using `git commit --amend` - Commit a file one part at a time: `git add --patch ` **OR** `ga --patch ` **OR** `gap ` - Useful when you made a lot of changes to a file and need to commit it - Enables you to commit certain parts of a file and not the entire thing - Note that if the file is not in the repository yet, you should do `git add -N ` or `ga -N ` - Go to the next section: `j` - Go to the previous section: `k` - Stage this section for the next commit: `y` - Do not stage this section for the next commit: `n` - Quit and do not stage this section or any of the remaining sections: `q` - Split the current section into smaller sections: `s` - Manually edit the current section: `e` Note that the `-u` flag means `set-(u)pstream-to`. It records the location so you don't have to set which remote to push or pull from every time. Also note that `git clone` makes a remote name of `origin` by default. This is why `git push -u origin master` is usually used. ### Working with Branches - Show all the branches: `git branch -a` - Checkout a different branch: `git checkout ` - Useful for 1) checking out the master or development branch, 2) checking out an upstream branch, and 3) checking out a feature branch - Create a new branch: `git checkout -b ` - Use `/` to describe your branches - For example, a fix for a compiler issue should have a branch name of `fix/description-of-compiler-issue` - Note that the branch should be descriptive but not too long (i.e. don't make it longer than above, since the example above is pretty long already) - Always create a new branch when submitting pull requests. This allows you to create multiple pull requests for different issues, prevent conflicts between your master branch and upstream, as well as some other things. - Delete a branch when you're done with it: `git branch -d ` - Push your changes to a different branch (i.e. your new branch): `git push origin ` **OR** `gp origin ` - Rename the current branch: `git branch -m ` ### Updating a Forked Repository If you haven't already, make sure that you have added a remote to the original (upstream) repository: `git remote add upstream ` 1. Fetch all the branches of that remote into `upstream/`: `git fetch upstream` 2. Change to the branch that you want to update (usually master): `git checkout master` 3. Rewrite that branch (usually master) with the changes upstream: `git rebase upstream/master` If a lot of people have forked your repository, then it may be better to use `git merge upstream/master` instead. This avoids rewriting history, but at the cost of clean pull requests. It may be necessary to force push your changes with `git push -f origin ` (usually master). Note that you should always make changes from an external branch then make a pull request from your external branch to avoid rewriting history. If you need to update your local repository but have local changes, you need to stash them first. 1. First fetch upstream like usual. 2. Then use `git stash` to store your changes temporarily. 3. Next rebase the branch you want to update with `upstream/` (usually master). 4. Finally use `git stash pop` to update your repository with the stashed changes. **NOTE**: To undo a git rebase, use `git reset --hard ORIG_HEAD` To fetch a specific branch from any repository (e.g. your repository): 1. Fetch the changes into a new branch: `git fetch :` 2. Checkout that branch: `git checkout ` ## Less common commands - Removes files to commit: `git rm ` - Delete all local changes in the repository: `git clean -f` - Show all the diffs and changes from the last N commits: `git log -p -` - Show the differences between your repository and a remote one: `git log -p master../master` - View all remotes for the current repository: `git remote -v` (e.g. GitHub mirror, friend's fork, upstream, etc.) - Show the location of a remote in a repository: `git ls-remote --get-url ` - You can search for `origin` to see the location you cloned from. - Show the entire contents of a commit, including diffs: `git show ` - Search for a string in the files of a git repository: `git grep ` **OR** `gg ` - Search for any tab characters in a repository: `git grep $'\t'` **OR** `ggt` - Search for any carriage returns in a repository: `git grep $'\r'` **OR** `ggr` - Merge all unpushed commits into a single commit: `git rebase -i origin/master` - Note that you are not done after this. You must also change `pick` to `squash` (or `s`) for all of the commits you want to merge. This is usually everything except your most recent commit. - Another window will open to let you combine all the commit messages into one big commit message - Merge the current branch with another one (usually master): `git merge ` - Change the remote location if your upstream repository URL changes: `git remote set-url origin git@address:user/repo.git` - Get an idea of how much has changed since the last commit: `git diff --stat` - Rebase the last N commits (i.e. edit them): `git rebase -i HEAD=N` - Apply the commit as-is: `pick` - Edit the commit message: `reword` - Edit the file(s) and/or commit message: `edit` - Merge the commit with the previous commit: `squash` - Merge the commit with the previous commit and discard the commit message: `fixup` - Rename a git directory to use different capitalization (e.g. from uppercase to lowercase): `git mv ` **THEN** `git mv ` **NOTE:** You should only merge commits with local commits that you haven't pushed yet. Doing this for upstream commits can cause problems for other people that have cloned your repository. ### Finding Bad Commits Before you begin, you should know a commit in which the program was working properly. Since you already know that issue is a part of the current revision, you can use `git bisect` to perform a binary search until the problem commit is found. 1. Start the search with `git bisect start` 2. Build and test the current commit to see if the problem is present. 3. If the problem is found, use `git bisect bad` 4. Otherwise, use `git bisect good` The problem commit is the "first bad commit" found through this process. Once you're done with finding the problem commit, use `git bisect reset` to go back to the repository's original state. **NOTE**: `git bisect run ./test` is a way to automate this process. To see the commits that have been tested so far, use `git bisect log` ### Working with Tags - Show all the tags in a repository: `git tag` - Create a new tag: `git tag -s -m ` - If `-m` is not given, git will open your editor to allow you to type a more detailed message - The tag name is usually a version number such as `v2.4.3` - Note that if for some reason you don't want to sign your tag, you should use `-a` instead. - View the saved data of a tag: `git show ` - Tag a specific commit instead of the current state in the repository: `git tag -s ` - Push a tag to the remote repository: `git push origin ` - Note that sharing a tag is the same as sharing remote branches - Push all tags to upstream: `git push --tags` - Easily change between versions of a repository (through tags): `git checkout ` - Update a previous version with new changes: `git checkout -b ` - Note that you should make a new tag for the updated commit since `` already refers to a commit and is not changed - For example, if you checkout tag `2.0` then the new tag can be, for example, `2.0.1` or `2.0a` - List all the tags in a given repository: `git tag -l` - Delete a tag (should rarely be used, if ever): `git tag -d ` ### Creating Patches You can make patch files for git repositories. This makes it so that other people can use your changes with ease. - Create patch files for the last N commits: `git format-patch HEAD~N` - Apply a patch to a git repository (unstaged): `git patch my.patch` - Apply a patch with its commit: `git am my.patch` - Apply all patches with their respective commits: `git am *.patch`