/home

Fri, 18 Nov 2022

Git cheat sheet

Git for daily use.
Updated as needed.

git CLI is not that hard once you understand branches are homeomorphic endofunctors mapping submanifolds of a Hilbert space.

Maybe the ony missing command is git unshit, but thanks to AGI we should get it very soon.

Knowing the git internal object model can be useful.

Sync with remote master branch (merge)

Download new changes and merge them:

git pull origin master

If one want to rebase rather than merge:

git pull origin master --rebase

Keep local HEAD branch and working copy files untouched:

git fetch origin

Clean merge process

git checkout feature/test
git pull 
git checkout master
git pull
git merge --no-commit test

If you want to keep a pre-defined branch topology, then you may pass --no-ff to the git merge command.

And then delete the feature branch:

git push -d origin feature/test     # remotely
git branch -d feature/test          # locally

Cancel a merge with conflicts

git merge --abort

Cancel a pushed commit

git reset --hard <last_known_good_commit>
git push -f

Tagging

create the tag

git tag -a MY_TAG -m "something" -m "another line"

OR

git tag -a MY_TAG -F <comment_file>

push the tag

git push origin --tags

OR

git push origin  MY_TAG

Remove Tag

Local tag first

git tag -d <tagname>

An then remote tag

git push --delete origin <tagname>

Branching

git checkout -b <my_branch>

Undo git add

git reset <file>

Amend a commit

git add history.txt
git commit --amend --no-edit
git push --force

History of one file

git log -p -- <file_path>

Files changed in a commit

git diff-tree --no-commit-id --name-only -r <commit id>

Archive/close a branch

You can tag the tip of the branch by archiving it, and then delete the branch.

git tag archive/<branchname> <branchname>
git branch -d <branchname>
git checkout master

The branch will be deleted, and can be retrieved later by checking out the tag, and recreating the branch.

git checkout archive/<branchname>
git checkout -b new_branch_name

Or more simply :

git checkout -b new_branch_name archive/<branchname>

Do not forget to share the tag to the server

git push archive/<branchname>

or to push all your tags

git push --tags

Force complete sync to master

Hard reset will lost all uncommitted and committed changes.

git fetch origin master
git reset --hard origin/master

Unable to update local ref

You might have errors like error: cannot lock ref 'refs/remotes/origin/feature/xxxx': is at 945f76b6da447ebfa6fd24d6f319eeddea39c6e8 but expected a8ab06614ecd2a5353da17c147f504775f6be9cc

First, remove stale lock files.
Second, fetch and clean references.
Thrid, remove unreferenced blobs.

find .git -type f -name '*.lock' -delete
git remote prune origin
git reflog expire --expire-unreachable=now --all
git gc --prune=now

Resolve case-sentive path collision

Under Windows 10 and 11, it is possible to enable case-sensitivity on a directory:

fsutil.exe file SetCaseSensitiveInfo <PATH-TO-DIR> enable

So the steps are:

  1. Enable case sensitivity on the target directory
  2. Clone the repository into this directory
  3. Resolve conflicts using git rm or git mv
  4. Commit/push

Sub-module best practices

Look at .gitmodules file in the root dir of the repo.

Add a submodule

git submodule add https://gitlab.com/example/repo.git path/to/submodule
git commit -m "add submodule"

Clone a repo with submodules

git clone --recurse-submodules https://gitlab.com/example/repo.git

Update a submodule

# update the content
cd path/to/submodule
git pull origin main

# push modifications
git add path/to/submodule
git commit -m "update submodule"

Locking submodule version

cd path/to/submodule
git checkout <commit-hash>  # or tag name...

cd ../
git add path/to/submodule
git commit -m "lock submodule to specific commit"

Automate submodule update (git hooks)

#!/bin/sh
# script/update-submodules.sh
git submodule update --init --recursive