This document is a WORK IN PROGRESS.
This is just a quick personal cheat sheet: treat its contents with caution!
Git¶
Git is distributed revision control and source code management software.
Reference(s)
- https://www.git-scm.com/docs/
- https://wiki.gentoo.org/wiki/Git
- https://wiki.archlinux.org/index.php/Git
- https://blog.microlinux.fr/formation-git/
- https://www.atlassian.com/git/tutorials/
- https://korben.info/apprendre-git-amusant.html
- https://github.com/jsomers/git-game
- https://github.com/git-learning-game/oh-my-git
- https://ohmygit.org/
- https://www.30secondsofcode.org/git/p/1
Table of contents¶
- Avoid dotfile madness
- Install
- Config
- Use
git config
.gitignore
git info exclude
git update-index
git init
git remote
git add
git stash
git commit
git revert
git reset
git restore
git clean
git fsck
git push
git pull
git branch
git rebase
git merge
git tag
git checkout
git switch
git cherry-pick
git diff
git difftool
git log
git show
git submodule
git filter-branch
andgit filter-repo
git blame
git sparse checkout
git hooks
git request-pull
git-sizer
- Pull/Merge request
- Signing Your Work
- Server
- Misc
- How to fork a repository
- How to mirror a repository
- Code review with Git
- Troubleshooting
- Bonus
Avoid dotfile madness¶
Prior to installation, make sure you stay in control of your home directory.
Prerequisite(s)
See how to handle Git related dotfiles.
Install¶
Config¶
Reference(s)
Configure git globally:
$ git config --global core.editor vi # set editor (e.g. `vi`)
$ git config --global color.ui true # enable color
$ git config --global init.defaultBranch main # set default name for the initial branch (e.g. `main`), the default one is `master`
SSH¶
Generate and copy a new SSH key¶
Create an ssh
key pair if you don't have one:
Copy the content of the public ssh
key to your clipboard
SSH in a GitLab project¶
Add the new SSH key to your GitLab account:
- Login to your GitLab account: https://gitlab.com/users/sign_in
- Click on your avatar in the upper right corner and select "Settings".
- Select the "SSH Keys" tab.
- Paste the content of your clipboard to the "Key" field (and optionally modify its title).
- Click on "Add key".
Test SSH with GitLab:
$ ssh-add ~/.config/ssh/ssh_key_name
$ ssh -T git@gitlab.com # answer 'yes' when asking if you want to continue connecting
SSH in a GitHub project¶
Add the new SSH key to your GitHub account:
- Login to your GitHub account: https://github.com/login
- Click on your avatar in the upper right corner and select "Settings".
- Select the "SSH and GPG Keys" tab.
- Click on "New SSH keys"
- Paste the content of your clipboard to the "Key" field (and optionally modify its title)
- Click on "Add SSH key"
Test SSH with GitHub:
$ ssh-add ~/.config/ssh/ssh_key_name
$ ssh -T git@github.com # answer 'yes' when asking if you want to continue connecting
SSH in a Bitbucket project¶
Add the new SSH key to your Bitbucket account:
-
Login to your Bitbucket account: https://bitbucket.org/
-
Click on your avatar in the lower left corner (to access your profile and settings) and select "Bitbucket Settings"
-
Select the "SSH Keys" tab.
-
Paste the content of your clipboard to the "Key" field and modify its title
-
Click on "Add key"
Test SSH with Bitbucket:
$ ssh-add ~/.config/ssh/ssh_key_name
$ ssh -T git@bitbucket.org # answer 'yes' when asking if you want to continue connecting
SSH tip¶
You can avoid the $ ssh-add ...
step by editing the ssh config file:
$ vi ~/.ssh/config
> ...
> Host gitlab.com
> IdentityFile ~/.ssh/ssh_key_name
>
> Host github.com
> IdentityFile ~/.ssh/ssh_key_name
>
> Host bitbucket.org
> IdentityFile ~/.ssh/ssh_key_name
> ...
Or simpler:
$ vi ~/.ssh/config
> ...
> Host *
> IdentityFile ~/.ssh/ssh_key_name
> IdentityFile ~/.ssh/other_ssh_key_name
> ...
Take advantage of SSH¶
If one wishes to take advantage of SSH with a Git project, one need to import this project the right way, e.g.:
Or one might switch a pre-existing repository to use SSH instead of HTTPS:
Use¶
git config
¶
Get and set repository or global options.
Reference(s)
-
Print all of your settings and where they are coming from:
-
Set user name and email address globally:
-
Set user name and email address project wide:
-
Set default git editor:
-
Define a template message for git commits (project wide):
.gitignore
¶
Specifies intentionally untracked files to ignore.
-
Create a
.gitignore
file and edit it (don't forget to commit it and push it afterwards): -
List the files that are included in the "exclude lists" (based on
.gitignore
) -
Remove the files that are included in the "exclude lists" (based on
.gitignore
) from the repository (not from disk): -
Check if a file is ignored or not (based on
.gitignore
): -
If a previously tracked file (or folder) has been added to the
gitignore
file, then make sure to untrack it:
Tip
If you still see a file (or folder) with $ git status
, after adding it to the .gitignore
file (even after running $ git rm --cached /path/to/file-or-folder
and after committing the
removed file/folder), then the $ git check-ignore -v ./path/to/file-or-folder
command
should also return no output (meaning that the file/folder is not ignored). This is probably
because the pattern of the .gitignore
file is "wrong", e.g. you added a comment after a
pattern (on the same line) instead of having a dedicated line for your comment.
git info exclude
¶
Reference(s)
The purpose of .git/info/exclude
is the same as .gitignore
: excluding files and/or folders (and
the syntax is the same).
But, as opposed to .gitignore
, .git/info/exclude
cannot be pushed/pulled, every developer
manages it's own .git/info/exclude
in it's local clone of the git repository. Hence what one
person ignores in his clone is not available in some other person's clone.
In general, files/ignore rules that have to be universally ignored should go in .gitignore
, and
otherwise files that you want to ignore only on your local clone should go into
.git/info/exclude
.
git update-index
¶
Register file contents in the working tree to the index
Reference(s)
$ git update-index
will not propagate with git, each user will have to run it independently.
-
Stop updating a specific file or folder (new local modifications won't be tracked). It's like telling git you want your own independent version of the file or folder (see https://stackoverflow.com/a/40272289).
But, if your local version differs from the remote one you will be notified with the following message: -
Cancel the previous command:
-
Tell git to stop checking a specific file or folder for changes, locally, assuming there won't be any. The assume unchanged index will be reset and file(s) overwritten if there are upstream changes to the file/folder (when you pull). This really is for optimization purpose, in order to speed up git process, e.g. when tracking a folder with a large number of files on a slow file system.
- Cancel the previous command:
git init
¶
Create an empty Git repository or reinitialize an existing one.
Reference(s)
-
Init a git repository in an existing folder
my-project
: -
Init a git repository
my-project
from scratch:
git remote
¶
Manage set of tracked repositories.
Reference(s)
-
Show your remotes:
-
Change a remote URL:
-
Add a remote (e.g. named
test
): -
Remove a remote (e.g. named
bad-remote
): -
Pull all branches from all your remotes:
-
Pull all branches from all your remotes by default:
-
Pull a specific branch (e.g. "master") from a specific remote (e.g. "test"):
-
Push to all your remotes, by adding them to
origin
:$ git remote set-url --add origin git@test-url.org/code.git # add test remote url to origin push list $ git remote -v > origin git@origin-url.org/repo.git (fetch) > origin git@origin-url.org/repo.git (push) > origin git@test-url.org/repo.git (push) > test git@test-url.org/repo.git (fetch) > test git@test-url.org/repo.git (push) $ git push # (push default branch "master") $ git push branch-name # (push specific branch "branch-name") $ git push -all # (push all branches)
-
Remove a remote from
origin
: -
Push all branches by default:
-
Push a specific branch (e.g. "master") to a specific remote (e.g. "test"):
-
Rename a remote:
git add
¶
Add file contents to the index.
Reference(s)
-
Stage all changes for commit:
-
Add a specific file to unstaged changes:
git stash
¶
Stash the changes in a dirty working directory away.
Reference(s)
-
Stash changes locally: (this will keep the changes in a separate change list called stash and clean the working directory. You can apply changes from the stash anytime)
-
Stash changes with a message:
-
List all the stashed changes:
-
Inspect the content of a stash:
-
Remove a stash:
-
Apply the most recent stash changes and remove it from the stash list:
-
Apply any stash from the list without removing the stash from the stash list:
git commit
¶
Record changes to the repository.
Reference(s)
-
Commit staged changes:
-
Edit previous commit message, if it hasn't been pushed already:
-
Git commit in the past:
-
Change the date of an existing commit:
git revert
¶
Given one or more existing commits, revert the changes introduced by theses commits. This requires a clean working tree (no modifications from the HEAD commit).
- Revert the project to a previous commit (e.g. with commit hash
0766c053
), with a single commit reverting all the changes:
git reset
¶
Reset current HEAD to the specified state.
Reference(s)
-
Remove/Undo "git add" before commit:
-
Removed staged and working directory changes:
-
Go 2 commits back:
-
Undo last commit (and never see it again):
-
Undo last commit (but it is preserved, one just go back of one commit):
git restore
¶
Restore working tree files.
Reference(s)
TODO
git clean
¶
Remove untracked files from the working tree.
Reference(s)
-
Remove untracked files:
-
Remove untracked and ignored files:
git fsck
¶
Verifies the connectivity and validity of the objects in the database.
Reference(s)
-
Print objects that exist but that are never directly used:
-
Write dangling objects into
.git/lost-found/commit/
or.git/lost-found/other/
, depending on type:
Tip
After a commit, you might end up pushing nothing, the commit seems to have "disappeared". This might be because your are not on the HEAD commit of your branch (maybe you previously checkout on a past commit, e.g. with a checkout on a tag), in this case you should not commit before doing a checkout at the HEAD of a branch. If you commit anyway, the commit will become "dangling", in this case you can find it and restore it like so:
git push
¶
Update remote refs along with associated objects.
Reference(s)
-
Push to the tracked master branch:
-
Push to a specified repository:
git pull
¶
Fetch from and integrate with another repository or a local branch.
Reference(s)
- Update the remote tracking branches for the repository you cloned from:
git branch
¶
List, create, or delete branches.
Reference(s)
- Create a new branch called
branch-name
, switch to it, add things and push it:
Note that, in your new branch, if you add new files and/or folders and those are empty and/or ignored, then you might still see them after switching back to another branch. In this case, just run the following in the other branch :
$ git clean -fd
-
Delete the branch
branch-name
locally: -
Completely delete the branch
branch-name
(locally and remotely, e.g. on remoteorigin
): -
Make an existing branch track a remote branch:
-
List all local and remote branches:
-
Print differences between the branch
master
and the branchbranch-name
: -
Print just which files differ, not how the content differ, between the branch
master
and the branchbranch-name
: -
Merge the branch
branch-name
intomaster
, and delete it afterwards (locally and remotely, e.g. from remoteorigin
):
git rebase
¶
Reapply commits on top of another base tip. git rebase
purpose is like to "cut" a branch and merge
it to the tip of another one."
Reference(s)
-
⚠️ Only rebase on a "private" branch, i.e. a branch where you are the only one working on it! This is sometimes considered a golden rule.
-
An interactive rebase is very useful to "clean up" the commit history of a branch (or a fork), e.g. before proposing a pull request. For example:
$ git rebase --interactive master pick 8714cb2 ... reword b749b62 ... edit aa25a46 ... pick fd62a63 ... exec make test1 squash f7276ec ... pick 0c1f4fd ... exec make test2 fixup 00b3c66 ... drop ded0ff0 ... break 516e3b6 ... pick bc778c0 ... pick e5c761a ... pick 9c9e3eb ... pick f739b57 ... pick bc6edb9 ... drop 0afd92a ... # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous # commit's log message, unless -C is used, in which case # keep only this commit's message; -c is same as -C but # opens the editor # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # create a merge commit using the original merge commit's # message (or the oneline, if no original merge commit was # specified); use -c <commit> to reword the commit message # u, update-ref <ref> = track a placeholder for the <ref> to be updated # to this position in the new commits. The <ref> is # updated at the end of the rebase # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted.
You can change any command in front of any commit hash, you can even re-order your commits.
-
Example of a rebase on a fork:
-
Example of a rebase including too much non-atomic commits (i.e. "bad" commits). In this case you might want to meld all commits together, then reset before that big commit in order to have all modifications unstaged. This way you can re-create all the commits you want in a more atomic way. For example :
$ git rebase -i upstream/master pick 8714cb2 ... fixup b749b62 ... fixup aa25a46 ... fixup fd62a63 ... fixup f7276ec ... fixup 0c1f4fd ... fixup 00b3c66 ... fixup ded0ff0 ... fixup 516e3b6 ... fixup bc778c0 ... fixup e5c761a ... fixup 9c9e3eb ... fixup f739b57 ... fixup bc6edb9 ... ... $ git reset "HEAD~" $ git add --patch # or `git add --interactive,`
Note that
git add --patch
might not allow you to finely select which line(s) of which file(s) you want to a add in a commit. If you feel limited by this behavior, some external tools exists and allow a more precise selection, for example fugitive.
WIP/TODO
See https://www.atlassian.com/git/tutorials/advanced-overview See https://www.atlassian.com/git/tutorials/merging-vs-rebasing See https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
git merge
¶
Join two or more development histories together.
Reference(s)
TODO
git tag
¶
Create, list, delete or verify a tag object signed with GPG.
-
List tags:
-
List tags associated to their own SHA-1 hash and the SHA-1 hash of the actual commit that the tag points to (lines ending with
^{}
). -
Create tag (release point):
-
Show a tag (e.g.
v1.4
) in more details: -
Add a tag in the past (e.g. at commit
9fceb02
): -
By default,
$ git push
doesn't transfer tags to remote servers. Here is how to transfer them: -
If you don't want to transfer all tags to remote servers, but just a specific one (e.g.
v1.4
): -
Delete a tag (e.g.
v1.4
): -
By default,
$ git push
won't transfer a deleted tag to remote servers. Here is how to transfer one (e.g.v1.4
): -
Move tag (e.g. move
v1.8
to current commit):
git checkout
¶
Switch branches or restore working tree files.
Reference(s)
-
Switch to tag/release point (e.g
v1.4
): -
Switch branch on a branch called "production":
-
Switch back to the master branch with the local changes made on "production": (this will switch branch and merge the local changes)
-
Restore the deleted file
hello.c
from the index: -
Reverts the
hello.c
file two revisions back on master branch: -
Create a bare new branch (one that has no commits on it):
-
Create a new branch from a different starting point, e.g. two commits behind:
git switch
¶
Switch branches.
Reference(s)
TODO
The git checkout command has a multitude of different jobs and meanings. That's why, pretty recently, the Git community decided to publish a new command: git switch. As the name implies, it was made specifically for the task of switching branches.
git cherry-pick
¶
Apply the changes introduced by some existing commits.
Reference(s)
-
Pick a single commit (from the same branch or not) and apply it to local work:
-
Pick a range of commit (from the same branch or not), excluding the first one - including the last one, and apply it to local work:
-
Pick a range of commit (from the same branch or not), including the first one - including the last one, and apply it to local work:
git diff
¶
Show changes between commits, commit and working tree, etc.
Reference(s)
-
Diff files WITHOUT considering them a part of git: (it can be used to diff files that are not in a git repository)
-
Diff staged files (after they have been "added"):
also--staged' is a synonym of
--cached`, so the following is valid: -
Diff one staged/cached files (after they have been "added"):
-
List files changed in
${commit_id}
: -
Check the changes between a local branch and it's remote branch:
-
difftastic
is a structural diff tool that compares files based on their syntax. It can be used withgit diff
(thanks to external diff support) like explained here.
git difftool
¶
A Git command that allows you to compare and edit files between revisions using common diff tools.
git difftool
is a frontend to git diff and accepts the same options and arguments.
Reference(s)
-
The same commands used with
git diff
can be run, just replacediff
bydifftool
: -
difftastic
is a structural diff tool that compares files based on their syntax. It can be used withgit difftool
like explained here.
git log
¶
Show commit logs.
Reference(s)
-
Print a one liner of your current position:
-
Print commit history of a set of files:
-
View commits that will be pushed:
-
View changes that are new on a feature branch:
-
See everything you have done, across branches, in a glance:
git show
¶
Show various types of objects.
Reference(s)
-
Show revisions can be identified with
:/text
. So, this will show the first commit that has "cool" in their message body: -
List files changed in
${commit_id}
, pretty way, meant to be user facing: -
Show a tag (e.g.
v1.4
) in more details:
git submodule
¶
Initialize, update or inspect sub modules.
Reference(s)
-
Clone a repository including sub modules:
-
If you forgot the
--recurse-submodules
option when cloning a repository, you can fetch the missing sub modules with the following command: -
Update all your sub modules to the latest tips of remote branches:
-
Update a specific sub module to the latest tip of remote branche:
-
Add a sub module to your repository:
-
Add a sub module, in a specific branch, to your repository:
-
Print sub modules status:
-
Print remote/origin URLs (e.g. to ensure that a sub module is pointing to the right repository):
-
Remove a sub module:
git filter-branch
and git filter-repo
¶
⚠️ WIP ⚠️
Reference(s)
- https://docs.gitlab.com/ee/user/project/repository/reducing_the_repo_size_using_git.html
- https://git-scm.com/docs/git-filter-branch
- https://github.com/newren/git-filter-repo
- https://github.com/newren/git-filter-repo#why-filter-repo-instead-of-other-alternatives
- https://github.com/newren/git-filter-repo/blob/main/INSTALL.md
Use git filter-repo
instead of git filter-branch
git filter-repo
is now recommended by the git project instead of git filter-branch
:
https://git-scm.com/docs/git-filter-branch#_warning.
Install
$ git clone https://github.com/newren/git-filter-repo.git
$ cd git-filter-repo
$ git checkout v2.34.0 # checkout to the latest release, e.g. v2.34.0 at the time of writing
$ make snag_docs
$ cp -a git-filter-repo $(git --exec-path)
$ cp -a git-filter-repo.1 $(git --man-path)/man1 && mandb
$ cp -a git-filter-repo.html $(git --html-path)
$ ln -s $(git --exec-path)/git-filter-repo \
$(python -c "import site; print(site.getsitepackages()[-1])")/git_filter_repo.py
- Remove an unwanted file from the entire git repository:
- A fresh clone is needed:
- Remove the unwanted file:
- Add
origin
back (ifgit filter-repo
removed it): - ⚠️ Make sure to review carefully any modification before pushing:
- Push to
origin
(⚠️ double check previous step before pushing): - If previous step didn't worked (e.g. you failed to push because the
git
server rejected it), this might be because of a protected branch, see:- https://comp.umsl.edu/gitlab/help/user/project/protected_branches.md
- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches
- https://confluence.atlassian.com/bitbucketserver/using-branch-permissions-776639807.html
TODO:
- https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#DISCUSSION
- https://docs.gitlab.com/ee/user/project/repository/reducing_the_repo_size_using_git.html
git blame
¶
Show what revision and author last modified each line of a file.
Reference(s)
- See who committed which line in a file
git sparse checkout
¶
This command is used to create sparse checkouts, which means that it changes the working tree from having all tracked files present, to only have a subset of them. It can also switch which subset of files are present, or undo and go back to having all tracked files present in the working copy.
Reference(s)
Example:
$ git init
$ git remote add -f origin https://git.server.com/user/project.git
$ git config core.sparseCheckout true
$ git sparse-checkout init
$ git pull origin master
$ git switch branch-name # optionally switch to any branch
$ tree .
.
$ git sparse-checkout set project/path/to/any/dir/or/file project/path/to/any/other/dir/or/file
$ git sparse-checkout list
project/path/to/any/dir/or/file
project/path/to/any/other/dir/or/file
$ tree .
.
└── project
└── path
└── to
└── any
├── dir
│ └── or
│ └── file
└── other
└── dir
└── or
└── file
Note that you can disable git sparse checkout
like so:
git hooks
¶
- Example of hooks:
.git/hooks
git request-pull
¶
Reference(s)
TODO
git-sizer
¶
Reference(s)
git-sizer
will compute various size metrics for a Git repository, it's very easy to use:
Pull/Merge request¶
Reference(s)
- https://docs.gitlab.com/ee/user/project/merge_requests/
- https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html
- https://docs.gitlab.com/ee/user/project/push_options.html
- https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
- https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request
TODO
Creating a merge request for GitLab¶
As of GitLab 11.10, if you're using git 2.10 or newer, you can automatically create a merge request from the command line like this (see https://docs.gitlab.com/ee/user/project/push_options.html):
A lot more useful options are available in order e.g. to add a title to the merge request, add a description, set the target of the merge request to a particular branch, mark it as a draft, add some labels, set a milestone, assign some users, etc:
$ git push -o merge_request.create \
-o merge_request.title="The title I want" \
-o merge_request.description="The description I want" \
-o merge_request.target=project_path/branch-name \
-o merge_request.draft \
-o merge_request.label="label1" -o merge_request.label="label2" \
-o merge_request.milestone="3.0" \
-o merge_request.assign="user1" -o merge_request.assign="user2"
Fetching a merge request from GitLab¶
WIP
$ git config remote.origin.fetch '+refs/merge-requests/*:refs/remotes/origin/merge-requests/*'
$ git fetch
$ git show-ref
6676fe2b810a3406747dfdaa5b4531db561b851e refs/heads/master
6676fe2b810a3406747dfdaa5b4531db561b851e refs/remotes/origin/HEAD
6676fe2b810a3406747dfdaa5b4531db561b851e refs/remotes/origin/master
6fd6fc72194c14c870fdb8e22089808f91b50bbc refs/remotes/origin/merge-requests/1/head
$ git switch ...
See https://www.jvt.me/posts/2019/01/19/git-ref-gitlab-merge-requests/.
Fetching a pull request from GitHub¶
$ git fetch origin pull/$PULL-REQUEST-ID/head:$YOUR-LOCAL-BRANCH-NAME
$ git switch $YOUR-LOCAL-BRANCH-NAME
Signing Your Work¶
Server¶
Misc¶
-
Reduce the size of a GitLab repository:
-
Sync a fork with the master repository:
$ git remote add upstream git@github.com:name/repo.git # Set a new repository $ git remote -v # Confirm new remote repository $ git fetch upstream # Get branches $ git branch -va # List local - remote branches $ git checkout master # Checkout local master branch $ git checkout -b new_branch # Create and checkout a new branch $ git merge upstream/master # Merge remote into local repository $ git show 83fb499 # Show what a commit did. $ git show 83fb499:path/fo/file.ext # Shows the file as it appeared at 83fb499. $ git diff branch_1 branch_2 # Check difference between branches $ git log # Show all the commits $ git status # Show the changes from last commit
-
Import commits from another repository:
-
Interactive rebase for the last 7 commits
-
Pull changes while overwriting any local commits:
-
Perform a shallow clone to only get latest commits (helps save data when cloning large repositories):
-
To unshallow a clone:
-
Remove all stale branches (ones that have been deleted on remote), so if you have a lot of useless branches, delete them on GitHub and then run this:
-
The following can be used to prune all remotes at once:
-
Revert a commit and keep the history of the reverted change as a separate revert commit:
-
Move your most recent commit from one branch and stage it on TARGET branch:
How to fork a repository¶
E.g. forking a public repository from GitHub to a private repository on GitLab.
A git repository can have more than one remote server, in this case we want to have two:
- One for our private repository on GitLab (will be the default one, called
origin
). - One to be connected to the upstream repository on GitHub, to be able to pull new changes (will
be called
upstream
).
Here is how to proceed:
-
Clone the GitHub repository you are interested in (e.g.
git@github.com:whatever/repo.git
): -
Rename the remote:
-
Create a new
blank
private project on GitLab (e.g.git@gitlab.com:whatever/private-repo.git
). -
Add the new origin to your repository:
-
Push the
master
branch to the private repository (you can push any other branch the same way): -
Push all tags to the private repository:
That's it!
-
To push to GitLab/master:
-
To retrieve updates from GitHub:
How to mirror a repository¶
$ git clone --bare git@some-git-server.xyz:path/to/repository-name.git
$ cd repository-name
$ git remote add mirror-name git@maybe-another-git-server.xyz:maybe/another/path/to/repository-name.git
$ git push mirror-name --mirror
Code review with Git¶
Reference(s)
Navigate to the branch to review¶
Visualize file changes¶
Configure git files
and git stat
:
$ vi $HOME/.bashrc # or ${ZDOTDIR:-${HOME}}/.zshrc or wherever
> ...
+ >
+ > # GIT
+ > export REVIEW_BASE="master"
$ vi ${XDG_CONFIG_HOME:-${HOME/.config}}/git/config
> ...
+ > [alias]
+ > # list files which have changed since REVIEW_BASE
+ > # (REVIEW_BASE defaults to 'master' in my zshrc)
+ > files = !git diff --name-only $(git merge-base HEAD \"$REVIEW_BASE\")
+ >
+ > # Same as above, but with a diff stat instead of just names
+ > # (better for interactive use)
+ > stat = !git diff --stat $(git merge-base HEAD \"$REVIEW_BASE\")
See which files have changed:
$ git status --show-stash
$ git stat # list files that changed from master
$ REVIEW_BASE=HEAD^ git stat # list files that have changed only from the last commit
Visualize file change frequency¶
Install git heatmap
(see https://github.com/jez/git-heatmap).
E.g. on Arch Linux (with AUR):
$ mkdir -p $HOME/apps/aur-apps
$ cd $HOME/apps/aur-apps/
$ git clone https://aur.archlinux.org/barchart.git
$ cd barchart
$ makepkg -si # install `barchart` dependency from AUR
$ mkdir -p $HOME/apps/src-apps
$ cd $HOME/apps/src-apps/
$ git clone https://github.com/jez/git-heatmap.git
$ cd git-heatmap
$ git checkout 0.10.3 # checkout to the latest tag/release (0.10.3 at the time of writing)
$ mkdir -p $HOME/bin
$ cd $HOME/bin
$ ln -s $HOME/apps/src-apps/git-heatmap/git-heatmap .
$ vi $HOME/.bashrc # or ${ZDOTDIR:-${HOME}}/.zshrc or wherever
> ...
+ >
+ > # PATH
+ > export PATH="$HOME/bin:$PATH"
$ source $HOME/.bashrc # or ${ZDOTDIR:-${HOME}}/.zshrc or wherever
$ git heatmap -h
See which files are the most modified:
Visualize relationships between files¶
- E.g. in Python: https://medium.com/illumination/visualize-dependencies-between-python-modules-d6e8e9a92c50)
Review the diffs¶
Configure git review
and git reviewone
:
$ vi ${XDG_CONFIG_HOME:-${HOME/.config}}/git/config
> ...
> [alias]
> ...
+ > # Open all files changed since REVIEW_BASE in Vim tabs. Then, run fugitive's `:Gdiff` in each
+ > # tab, and finally tell vim-gitgutter to show +/- for changes since REVIEW_BASE
+ > review = !nvim -p $(git files) +\"tabdo Gvdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\"
+ > vreview = !nvim -p $(git files) +\"tabdo Gvdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\"
+ > hreview = !nvim -p $(git files) +\"tabdo Ghdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\"
+ >
+ > # Same as the above, except specify names of files as arguments, instead of opening all files:
+ > # (e.g. `$ git reviewone test1.rs test2.rs`)
+ > reviewone = !nvim -p +\"tabdo Gdiff $REVIEW_BASE\" +\"let g:gitgutter_diff_base = '$REVIEW_BASE'\"
Open diffs of all the changed files:
Open diffs of the specified files:
Troubleshooting¶
- When cloning a repository, if the following error appears: Then do the following (https://stackoverflow.com/questions/21277806/fatal-early-eof-fatal-index-pack-failed):
Bonus¶
git lfs
¶
install¶
config¶
use¶
In each Git repository where you want to use Git LFS, select the file types you'd like Git LFS to
manage (or directly edit your .gitattributes
). You can configure additional file extensions at
anytime. E.g. any *.psd
file:
```console
$ git lfs track "*.psd"
```
Now make sure .gitattributes
is tracked:
```console
$ git add .gitattributes
```
Note that defining the file types Git LFS should track will not, by itself, convert any
pre-existing files to Git LFS, such as files on other branches or in your prior commit history. To
do that, use the git lfs migrate
command, which has a range of options designed to suit various
potential use cases.
Finaly, just commit and push as you normally would; for instance, if your current branch is named main:
```console
$ git add file.psd
$ git commit -m "Add design file"
$ git push origin main
```
git annex
¶
Monitoring¶
- https://github.com/mvisonneau/gitlab-ci-pipelines-exporter
- https://blog.stephane-robert.info/post/gitlab-montoring-several-pipelines/
- https://about.gitlab.com/pricing/faq-consumption-cicd/
Games¶
- https://github.com/jsomers/git-game
- https://github.com/git-learning-game/oh-my-git
- https://ohmygit.org/
If this cheat sheet has been useful to you, then please consider leaving a star here.