Git Notes

Generating SSH keys (copy paste from Github)

$ ssh-keygen -t ed25519 -C "your_email@example.com"

# legacy
# $ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

$ eval $(ssh-agent -s)
$ ssh-add ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub

Commands easy to forget

$ git remote -v
$ git rebase -i branchname or commit hash
$ git log --stat
$ git log --graph
$ git checkout other-branch the/path/to/yourfile
$ git diff yourbranch otherbranch -- file
$ git merge --reset

Tags

Annotated (with message) and light-weight (no message).

$ git tag
$ git push origin tag_name
$ git show tag_name
$ git log -1 tag_name

Annoying line-ending differences

Checkout Windows-style, commit Unix-style

git config core.autocrlf true

Git will convert LF to CRLF when checking out text files. When committing text files, CRLF will be converted to LF. For cross-platform projects, this is the recommended setting on Windows.

Checkout as-is, commit Unix-style

git config core.autocrlf input

Git will not perform any conversion when checking out text files. When committing text files, CRLF will be converted to LF. For cross-platform projects this is the recommended setting on Unix.

Checkout as-is, commit as-is

git config core.autocrlf false

Git will not perform any conversions when checking out or committing text files. Choosing this option is not recommended for cross-platform projects.

Gitignore

To create a user .gitignore and not global, do:

# go to your repo .git folder
$ cd <your-repo>/.git

# populate with your files/folders
$ nano .user_gitignore

# add it to your config
$ git config core.excludesfile .git/.user_gitignore

# you can see it is added
$ git config -l

To create a global .gitignore, do:

# or where desired
$ git config --global core.excludesfile ~/.global_gitignore

Using HEAD^ and HEAD~

Basically HEAD^ is doing a BFS traversal while HEAD~ only recognizes the first parent but can select the leaves using the caret e.g. H = A^^^2 = A~2^2

G   H   I   J
 \ /     \ /
  D   E   F
   \  |  / \
    \ | /   |
     \|/    |
      B     C
       \   /
        \ /
         A

A =      = A^0
B = A^   = A^1     = A~1
C = A^2  = A^2
D = A^^  = A^1^1   = A~2
E = B^2  = A^^2
F = B^3  = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2  = B^^2    = A^^^2  = A~2^2
I = F^   = B^3^    = A^^3^
J = F^2  = B^3^2   = A^^3^2

Using multiple SSH keys

Useful if you have bitbucket, github etc. and want to use different ssh keys instead of sharing them - for security inconvenience reasons

  1. Generate a ssh key and add it to your account e.g. bitbucket_rsa

  2. Edit your ~/.ssh/config:

    # ~/.ssh/config
    
    # Github
    Host github-foobar
            HostName github.com
            User git
            IdentityFile ~/.ssh/id_rsa
    
    # Bitbucket
    Host bitbucket-deadbeef
            HostName bitbucket.com
            User git
            IdentityFile ~/.ssh/bitbucket_rsa
  3. Now you can add a new remote that uses your new ssh key

    # git remote add <remote_name> git@<new_host>:<username>/<repo>.git
    $ git remote add bitbucket git@bitbucket-deadbeef:deadbeef/some-repo.git
  4. Now we can push to our new remote with our new ssh key!

    $ git fetch bitbucket master
    $ git push bitbucket master

Submodules

Adding changes in the submodule

From Stack Overflow:

A submodule is its own repo/work-area, with its own .git directory. When cloning, use the --recurse-submodules.

So, first commit/push your submodule's changes:

$ cd path/to/submodule
$ git add <stuff>
$ git commit -m "submodule changes"
$ git push

Then, update your main project to track the updated version of the submodule:

$ cd /main/project
$ git add path/to/submodule
$ git commit -m "updated my submodule"
$ git push

Updating all submodules

If you want to update all your submodules to the latest commit available from their remotes:

$ git submodule foreach git pull origin master

Last updated