Commands
If you are new to git entirely, I'd recommend checking out https://learngitbranching.js.org and running through the examples they host there.
Create a Repository
To create a repository, just create a directory or enter the root directory of the project you want to turn into a repository, and type git init
. This initializes the directory as a local repository. To add the repository to GitHub and track it remotely, you'll need to login to GitHub and click 'New Repository', name the repository the same as your root folder and continue. GitHub will provide you with the rest of the instructions, but for completeness, tweak the lines below to push your local repository to your new remote on GitHub -
git remote add origin git@github.com:<username>/<reponame>.git
git push -u origin master
We just created the origin
remote. This is the remote that is displayed and tracked on GitHub, when you clone your repository you are on a local remote, which means until you git push <remote> <branch>
your changes will only be saved and tracked on your local machine.
Using a remote via SSH SSH such as the above git@github.com:<username>/<reponame>.git
requires you have configured an SSH key with your GitHub account that is associated with the machine you are pushing from. If you haven't already, check out Creating SSH Login Keys and simply cat ~/.ssh/<USERKEY>.pub
the public key of your user and copy it over into your GitHub settings.
If you'd rather not mess with things like this, see how to create a Person Access Token below.
Authenticating with Git
There are many ways to authenticate with Git when pushing to remote repositories. See some of the below for examples.
Credential Caching
If you don’t want to
authenticateauthenticate every time you push, you can set up a “credential cache”. The simplest is just to keep it in memory for a few minutes, which you can easily set up by running git config --global credential.helper cache.
https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage#_credential_caching
SSH Keys
You can use ssh-keygen
to generate a key and the manually add the key to your GitHub profile.
To do this, run ssh-keygen -t ed25519
and follow the prompts. Be sure to include the file path when naming your key, or the key will be output into your working directory. Once generated, simply cat user_ed25519.pub
and copy / paste your public key into the field within your settings on GitHub.To do this, you'll need to run git remote set-url origin git@github.com:User/UserRepo.git
in order to configure your local repository to use SSH private keys when connecting to git. For more on ssh-keygen, check out Creating SSH Login Keys.
Personal Access Tokens
Alternatively, you could generate a static Personal Access Token - a token that once generated can be paired with a YubiKey or similar product. This allows you to clone / work from anywhere without having to provision or SSH keys or manage long passwords / 2FA methods. Plug your key into USB and tap your desired configuration and the static access key will be input, allowing immediate access for this one time. So, every time you push, unless you configure otherwise, you will have to enter this token by tapping the YubiKey.
Commit Guidelines
Before you commit, run git diff --check
, which identifies possible whitespace errors and lists them for you.
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.
Use git add --patch
to partially stage files (covered in detail in https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging#_interactive_staging )
The project snapshot at the tip of the branch is identical whether you do one commit or five, as long as all the changes are added at some point
As a general rule, your commit messages should start with a single line that’s no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation
git log --pretty=oneline
shows a terse history mapping containing the commit id and the summary
If the config option merge.summary is set, the summaries from all merged commits will make their way into the merge commit message
git pull --rebase
What’s happening here? Git will rewind (undo) all of your local commits, pull down the remote commits then replay your local commits on top of the newly pulled remote commits. If any conflicts arise that git can’t handle you’ll be given the opportunity to manually merge the commits then simply rungit rebase --continue
to carry on replaying your local commits.
git shortlog
uses summary lines in the changelog-like output it produces -
git format-patch
, git send-email
, and related tools use it as the subject for emails.
Reflogs, a local history accessible with git reflog
, is intended to help you recover from stupid mistakes by providing the hashes along with output similar to git shortlog
.
Pushing
If we run ... git push <remote> serverfix
Git automatically expands the serverfix
branchname out to refs/heads/serverfix:refs/heads/serverfix
Where the general sytax is local:remote
..
Always check your branch with git status
before pushing! Especially when pushing to a shared repository, this could have unintended consequences and result in a messy history. See Resolving Conflicts below if you are having conflict issues.
You can use this format to push a local branch into a remote branch that is named differently. If you didn’t want it to be called serverfix
on the remote, you could instead run git push origin serverfix:awesomebranch
to push your local serverfix
branch to the awesomebranch
branch on the remote project.
Should you see the errors below when attempting to push, see the Pull / Merge > Resolving Conflicts section of this page for steps on merging your branches, resolving the conflicts, and then completing your push.
[kapper@kanjaro 6-complex-numbers]$ git push origin v0.2
To github.com:shaunrd0/CMake.git
! [rejected] v0.2 -> v0.2 (non-fast-forward)
error: failed to push some refs to 'git@github.com:shaunrd0/CMake.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Shared Remote Server Workflow
*You should also be able to share your branches by pushing them to a shared server, working with others on shared branches and rebasing your branches before they are shared. This being said, it’s possible to have a workflow where each developer has write access to their own public repository and read access to everyone else’s -
- The project maintainer pushes to their public repository.
- A contributor clones that repository and makes changes.
- The contributor pushes to their own public copy.
- The contributor sends the maintainer an email asking them to pull changes.
- The maintainer adds the contributor’s repository as a remote and merges locally.
- The maintainer pushes merged changes to the main repository.
Reversing Changes
Use Use git reset <remote>
for local changes -
# one commit in the past
git reset HEAD^
# 2 commits in the past
git reset HEAD^^
# 2 commits in the past
git reset HEAD~2
# 3 commits in the past
git reset HEAD~3
Use Use git revert <remote>
for changes that have already been pushed to a remote -
# 1 commit in the past
git revert HEAD
# 2 commit in the past
git revert HEAD^
# 3 commits in the past
git revert HEAD^^
# 3 commits in the past
git revert HEAD~2
# 4 commits in the past
git revert HEAD~3
# Note that HEAD could be replaced with v0.2, or any active branch that exists on the remote
Branching
Basic git branch commands -
# checkout and create new branch if it doesnt exist
git checkout -b branchname
git log --all --graph --decorate --oneline --simplify-by-decoration
will output your history in a format similar to the Network Graph on GitHub
[kapper@kanjaro cmake]$ git log --all --graph --decorate --oneline --simplify-by-decoration
* 8221652 (HEAD -> master, origin/master, origin/HEAD) merge v0.4 into master
* 27e6e1c (origin/v0.4, v0.4) Fix for tab spacing in vim
| * feb1da1 (refs/stash) WIP on master: 807e0b3 Reorganized C problem 4
|/
* 807e0b3 (origin/v0.3) Reorganized C problem 4
* 2fc4266 (origin/v0.2) Finishing up v0.2
| * 9187276 (origin/v0.1) Cleaned up the README.
|/
* f1b858b Initial commit of first CMake project
[kapper@kanjaro cmake]$
The output can be formatted further, and linked with aliases within git -
git config --global alias.lg "log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
There are also other simpler options for similar output with less information -
git show-branch
git show-branch --all
Alternatively, if you would rather a GUI - run gitk
- provided it's configured correctly.
To delete a branch, local or remote, see the commands below -
# Remove a local branch
git branch -d the_local_branch
# To remove a remote branch (if you know what you are doing!)
git push origin :the_remote_branch
git push origin --delete the_remote_branch
Pull / Merge
Before merging, commit and push a 'checkpoint' to your version or feature branch. If you do not, git will squash the history from your branch into master - this commit can serve as a reference for changes merged into master later on. Should you forget to do this, the merge could still be traced with more effort.
merge master
into the test
first to resolve any conflicts on the the test
branch itself. After the test
branch is clean, up-to-date, and pushed to origin, I'll git checkout master
and git merge test
.
git merge origin/master
. If you want to fast-forward, run git merge --ff-only origin/master
The --squash
option takes all the work on the merged branch and squashes it into one changeset producing the repository state as if a real merge happened, without actually making a merge commit.
Also the --no-commit
option can be useful to delay the merge commit in case of the default merge process.
Resolving Conflicts
Problems pushing your local changes to a remote (origin) ?
git pull <remote> <branch>
and resolve the conflicts by following the instructions below .
When attempting to pull or merge branches, there can sometimes be new changes to the same content within the same files on the two different branches. Since git wants to be sure that you retain the changes you want, it pauses our merge and prompts us to resolve these conflicts before creating a final commit to finish our merge.
[kapper@kanjaro 6-complex-numbers]$ git pull origin v0.2
From github.com:shaunrd0/CMake
* branch v0.2 -> FETCH_HEAD
Auto-merging 4-Ch2-course-laucher/CMakeLists.txt
CONFLICT (content): Merge conflict in 4-Ch2-course-laucher/CMakeLists.txt
CONFLICT (add/add): Merge conflict in 4-Ch2-course-laucher/4-problems/CMakeLists.txt
Auto-merging 4-Ch2-course-laucher/4-problems/CMakeLists.txt
Automatic merge failed; fix conflicts and then commit the result.
Below, we can see that my branch has conflicts with 4-Ch2-course-launcher/CMakeLists.txt
- So, to resolve these, we would run vim 4-Ch2-course-launcher/CMakeLists.txt
On branch v0.2
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both added: 4-Ch2-course-laucher/4-problems/CMakeLists.txt
both modified: 4-Ch2-course-laucher/CMakeLists.txt
no changes added to commit (use "git add" and/or "git commit -a")
vim <path/to/conflict/file>
and you will notice syntax similar to the below has been added to your file -
Some text in a file that has no conflict.
<<<<<<< HEAD
Some text that was changed on the local HEAD.
=======
Some text that was also changed on the remote we are attempting to merge with
>>>>>>> feature-branch
Some more text in a file that has no conflict.
All that Git is asking us to do here is delete the changes that we don't wish to keep, and then git commit -m "Commit message"
to complete our merge. If you want to abort the merge, run git status
to see how, or just run run git merge --abort
.
So, in this case if we wish to keep the changes that are on our local HEAD
, and overwrite the changes on our feature-branch
. Just modify the file, deleting all of the added syntax from the merge conflicts described by git, and any changes that may go with them -
Some text in a file that has no conflict.
Some text that was changed on the local HEAD.
Some more text in a file that has no conflict.
Our merge conflict is resolved. check git status
, stage your changes with git add
and make the commit to finish the merge.
Stashing
To stash changes in git, simply run the commands below -
[kapper@kanjaro cmake]$git stash
Saved working directory and index state WIP on master: xxxxxxx Reorganized C problem 4
[kapper@kanjaro cmake]$ git stash list
stash@{0}: WIP on master: xxxxxxx Reorganized C problem 4
[kapper@kanjaro cmake]$
This is useful stash your local changes, pull from the remote, resolve any conflicts from your stashed changes and push back to the remote so other contributors can see your work.
Rebase
Rebasing can be used to move your work to another branch without merging the branches entirely. This is useful if the branch has more development planned or if you would like to keep the branch open for other reasons. This can also be used to modify the history, if you are careful and know what you are doing.
git rebase <remote>
OR
git rebase master
git rebase fix
etc..
git rebase --interactive
or git rebase -i
provides the summary for each commit in the editor it invokes
You may want to use rebase -i <commit hash>
to squash your work down to a single commit, or rearrange the work in the commits to make the patch easier for the maintainer to review
https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#_rewriting_history
Patching
To apply a patch generated by format-patch, you use git am
(the command is named am
as it is used to "apply a series of patches from a mailbox").
If you run a mail client that can save several emails out in mbox format, you can save entire patch series into a file and then use git am to apply them one at a time.
git diff --check
, which identifies possible whitespace errors and lists them for you.