git cheat sheet / GitLab cheat sheet / GitHub cheat sheet

A little cheat sheet for using git


What do you need to know that confused me? Well here is a short list

- Git stores all information repos in local directory called .git in the project root directory. So you can have a complete repo on a floppy disk if you like and it fits.

- Very important to understand: If you are on one branch and makes changes to the files and then forgetting to  commit the changes to the branch, then these changes will continue to exist even AFTER switching branch. For the uninformed, it looks like the branching is broken - you switched branch and the changes you wanted to throw aside into a branch is still there. But you need to COMMIT the changes to the working branch (or stash them) BEFORE switching to another branch. Then it works.

- Git mostly talks to the outer world through clone, push and pull. Aside from that
you are working locally.

- A good way to learn how git works is to install it with apt-get install git, make a test directory, make a text file, init a new repo and add the text file and make branches and play around. Pretty fast you learn the basics. Just remember the thing noted about forgetting to commit before switching to another branch, or you'll get confused.

- Git uses vi editor when it detects merge changes that it cannot handle on it's own. You are encouraged to learn vi (it pays off) or edit git configuration to switch default editor.

- It matters what branch you stand in when making a new branch. If you make a new branch B standing in branch A, then B WILL be based on branch A. This is a HUGE pitfall if you are not aware of it. If you don't want this effect, make sure you switch to master BEFORE creating a new branch, or you will get the changes from the current branch merged into master when merging the new branch.

- Git silently fetches changes/differences from the remote repo. So if you are working in a branch and diffs it against your master and it suddenly shows strange changes, then switch to master, it will likely tell you that your branch is after origin/master. Pull it and rebase.


A list of git commands

<Texts> show where to put in info.

Setup - do this first
	sudo apt-get install git

Configuration, do also this first to setup your user and activate coloring
        git config --global init.defaultBranch main
	git config --global user.name "firstname lastname"
	git config --global user.email "valid@email.address"
	git config --global color.ui auto	
	git config --global core.editor vim	
	git config --global push.default simple

Also set the strategy when pulling and applying local commits:
	git config --global pull.rebase true

Explanation for the pull.rebase setting:
	"rebasing
	If you pull remote changes with the flag --rebase, then your local changes are 
	reapplied on top of the remote changes.
	[...]
	merging
	If you pull remote changes with the flag --merge, which is also the default, then
	your local changes are merged with the remote changes. This results in a merge
	commit that points to the latest local commit and the latest remote commit. 
	[...]
	best practice
	It is best practice to always rebase your local commits when you pull before pushing
	them. As nobody knows your commits yet, nobody will be confused when they are
	rebased but the additional commit of a merge would be unnecessarily confusing.
	Published commits are, however, usually merged, for example when branches are merged."

	Source: https://sdqweb.ipd.kit.edu/wiki/Git_pull_--rebase_vs._--merge

Configuration for local repos, if you want to go under another e-mail for specific projects, standing in the repo root dir:
	git config user.email "different.valid@email.address"

List current configuration, note that if you are standing in a repo with different settings, then those are displayed last, overriding the ones above:
	git config --list

NOTE: It is advisable to also set some of these running as root if you sometimes are logged in as root. Like global user.name, user.email, color.ui and core.editor. Check with the list command above and compare the output for your user with root so they are identic, or as you want to have it.

Also make sure your local time is correct by installing ntp to avoid wrong commit dates:
	sudo apt-get install ntp
        sudo service ntp start

NTP status can be checked with:
        ntpq -p
        systemctl status ntp

Clone a repo - to download a repo from somewhere, be ready with username and password
This creates a subdirectory with the project name.
	git clone https://github.com/<username>/<projectname>.git

Reset current situation to original before files was edited
	git reset --hard HEAD

Fetch latest changes from remote repo
	git pull 

Create a new local repo (makes .git directory)
	git init 
	
Remove the local repo (simply remove the .git directory, that's all)
	rm -rf .git/

Add files / stage files before doing a commit:
	git add ./ OR git .
	
Store the current changes as a commit
	(git add <changed files according to git status>)
	git commit -m "<Write what has been changed here>"

Create a new (local?) branch
	git checkout master (VERY important, new branch will be based on current branch)
	git checkout -b <branch name>
	OR
	git branch <branch name>
	git checkout <branch name>

	To save changes in a branch, do a regular commit, like
	git add <changed files according to git status>
	git commit -m "<Write what has been changed here"

	NOTE! it is VERY important to add files before committing, this "stages"
	changed files. If you don't do this and switch branch, you will
	find that the changes in the branch are still there even after
	switching branch. This is confusing.

Switch to another branch, replace <branch name> with master to go to master
	git checkout <branch name>

Rename local branch
	git branch -m <oldname> <newname>

List available remote branches:
	git branch -v -a

Fetch a remote branch and prepare it locally(?):
	git branch <branch name> remotes/origin/<branch name>

NOTE about name:

	<branch name> MUST reflect the remote branch name after remotes/origin, it may also contain slashes.
	Otherwise git will complain because the remote and local branch names differ.

	git checkout <branch name>
	git pull

Rename a branch
	git branch -m <oldname> <newname>

Push a remote branch to remote
	git push <remote-name> <local-branch-name>:<remote-branch-name>
	<remote-name> = origin (most often)
	Next time you do git push, you will be prompted to:
	git push --set-upstream origin <remote? branch name>

Work with someone elses (remote) branches on GitHub - 2017 edition
For some reason you suddenly don't need to mess around with origins and stuff.
You can work with remote branches like they were local.

	git clone <.git link>
	git checkout <branch name>
	git add <files>
	git commit -m "<reason text>"
	git push

Note that this seems to create a local copy of the branch you're checking out.
Also note that you need to be collaborator (participant?) on the branch.

Remove/delete/untrack a file, this will not delete the file from the file system, just from Git
	git rm filnamn
	git commit -a -m "<Write why file was removed>"
	
Remove local branch
	git branch -d <branch name>
	
Merge branches, first switch to the branch you want to keep, then request a merge
	git checkout <branch name to keep>
	git merge <branch name to merge into the one to keep>
	git branch -d <branch name to merge>

Merge branch into master:
	(git rebase on branch... git pull etc. is good before)
	git checkout master
	git merge <branch to merge>
	git push

Rebase, merge, push and delete:
	git checkout master
	git pull
	git checkout <branchname>
	git rebase master
	git checkout master
	git merge <branchname>
	git push
	git branch -d <branchname>
	git push origin --delete <remote-branchname>

	Note: do NOT forget to pull on master first, otherwise you will miss latest updates.

Update a branch to master:
	git checkout <branchname>
	git rebase master <branchname> 
	(<branchname> is not necessary)

Resolving a conflict during a rebase:
	git checkout <branch>
	git rebase
	<conflict appears>

	Edit the files, find HEAD text, take the correct part, delete the rest

	git add <edited files>
	(git commit -m "What has been changed..." - maybe not needed)
	git rebase --continue
	git push --force

Check current uncommitted difference/changes
	git diff

Check total diff for branch to master, standing in the actual branch
	git diff HEAD master

Check current uncommitted but staged (added) changes:
	git diff --cached

Check unsaved changes, files that have not been added and so on
	git status

Check commit log
	git log

Show specific commit and the data committed
	git show <commit hash>

Reset file - revert/undo file changes
	git checkout -- <filename or folder>

Reset file to master or other branch - revert/udo file changes
        git checkout origin/master <filename or folder>
        or for branch other than master:
        git checkout origin/<branch name to "revert" to> <filename or folder>
	
Check configured remote repos/servers
	git remote 
	OR for mer info
	git remove -v
	
	"origin" is the default name for the remote server

Ignore files
	Local folder only, not affecting repo .gitignore: add to .git/info/exclude
	Following the repo: add to .gitignore

Ignore tracked files locally
	git update-index --assume-unchanged <file name>

Un-ignore tracked files locally
	git update-index --no-assume-unchanged <file name>

List ignore tracked files locally
	git ls-files -v | grep -e "^[hsmrck]"

Ignore tracked files locally, alternative, causes conflicts when changes are upstream:
	git update-index --skip-worktree <file name>

Un-ignore tracked files locally, alternative:
	git update-index --no-skip-worktree <file_name>

List ignore tracked files locally, alternative:
	git ls-files -v|grep '^S'

View change history for one file
	git log -p <filename>

Combine (squash) last X commits:

git log (to check the commits, count the ones you want to combine, then put that number where the X is below.)
git reset --soft HEAD~X
git commit

Edit other commit messages than the last one (that can be done with git commit --amend), 
	git log
	Count the commits down to and including the one to edit and put in X:
	git rebase -i HEAD~X
	In the editor, replace pick with reword on the line to edit, save the file.
	A new editor will come up, edit the commit.

	Source: https://stackoverflow.com/questions/179123/how-to-modify-existing-unpushed-commit-messages

Put in changes before commit X:

	Make a backup of the repository
	Find the commit to reverse to, if initial, go down to the first, copy the id:
	git log
	Create a new branch from master using the commit:
	git checkout --orphan new-master <id-of-the-commit>
	If you want to start clean, remove all files:
	git rm -rf .
	Check if there are leftovers and remove them with rm -rf as usual files.
	
	You are now ready to move your changes into the directories, do so.
	Then to commit, do as usual with the addition of a date:
	git commit --date="<YYYY-MM-DD H:i:s>" --message="<message>
	
	Now lets rebase master on top of this branch, be prepared for conflicts:
	git rebase --onto new-master --root master

	Solve any eventual conflicts.

	To check that the rebased master is the same state as it was before the rebase, do this:
		git diff master@{1}
	Or this:
		git diff orig_head
	No output should be returned.

	Source: https://stackoverflow.com/questions/16762160/add-commits-before-root-commit-in-git

Revert a commit:
	Create a branch, if you intend to make a pull request on GitHub.

	git revert <commit-id>
	
	This makes a new commit that reverts the commit and opens the editor to write a commit message.



GitHub/Bitbucket - authenticate Linux login using SSH keys without username and password

Go to your local ssh directory:
cd ~/.ssh/

Check for ssh key:
ls -la|grep id_rsa.pub

If it ain't there, generate it:
ssh-keygen -t rsa -C "local-username@hostname"

NOTE, enter the login you use to login to the host and hostname of computer in the e-mail, it it's not necessary to enter your own email here as this key is attached to the current host you are on. So if you login with user and the hostname is host, enter user@host.

To get username:
echo $USER

To get hostname:
echo $HOSTNAME (or cat /etc/hostname)

You have now generated 2 files, id_rsa and id_rsa.pub. Never share id_rsa, it's your private key.
But output contents of id_rsa.pub:

cat id_rsa.pub

Copy the contents.

For Bitbucket:

Click on the user icon in the top right, then go to Settings, Personal Settings, Security, SSH Keys.

Then click Add key, fill in a fitting label like Computer, paste the contents from id_rsa.pub in Key and click Add key.

For Github:

Go to https://github.com/settings/keys (or your image in the top right, then Settings in the menu, then Keys in the left panel) and login with your GitHub password.

Click New SSH Key and paste the contents from id_rsa.pub and save it.

Go to your project root location (the folder with the .git folder in it) and do:
git remote -v

Make sure it does NOT use https, this is not working for example:
origin    https://.../.git (fetch)
origin    https://.../.git (push)

If it does, then you need to change origin so it doesn't use HTTPS.

For GitHub:
git remote set-url origin git@github.com:<repository owner>/<repository>.git

For Bitbucket:
git remote set-url origin git@bitbucket.org:<repository owner>/<repository>.git

To switch back to HTTPS do the following.

For GitHub:
git remote set-url origin https://github.com/<repository owner>/<repository>.git

For Bitbucket:
git remote set-url origin https://<your bitbucket username>@bitbucket.org/<repository owner>/<repository>.git


X11 Forwarding and GitHub

You may get "X11 forwarding failed on channel 0" when connecting to Bitbucket or GitHub after switching to passwordless authentication.

To solve this, edit your local ~/.ssh/config file so it disables X11 Forwarding for GitHub:

Host bitbucket.org
        ForwardX11 no

Host github.com
	ForwardX11 no

Host *
	ForwardX11 yes

Reference: https://unix.stackexchange.com/questions/240013/x11-forwarding-request-failed-when-connecting-to-github-com


Publish existing repository to GitLab


Create the project on GitLab - click on the plus sign (+) in the top bar, then go New project. Fill in the name and the description.

Copy the HTTPS address to the console, like if you should pull it.

In the terminal, do:
git remote add origin https://gitlab.com/<username>/<project>.git

Do a first push:
git push --set-upstream origin master

Set it to track, otherwise it will not work:
git branch --set-upstream-to=origin/master master

Go back to GitLab and in the project go Settings, Repository, Protected Branches, under Protected branch, click Unprotect on master.

In the terminal, push up new changes if any:
git push


Mirror from GitLab to GitHub

Additional things you may want to do is to mirror the project from GitLab to GitHub, set project description and title.

To mirror you need to grant GitLab access to GitHub using a key.

In GitHub, click on the user profile picture in the top right, go to Settings, Developer settings, Personal access token.

Click Generate new token. Name it GitLab or something and check repo and delete_repo.
You now get a token that works as a limited password for GitHub.

Create a new empty project in GitHub with the same name as on GitLab.

Copy the full address to the project and go to GitLab and the project.

Go to project settings, Repository and Push to a remote repository.
Fill in the GitHub address like this:
https://<username>@github.com/<username>/<project>.git

In Authentication method, select Password.

In Password, fill in the token.

Save it. To test, click the Repository Settings page subtitle and go to Push to a remote repository again and click the new hidden Update now button.


Mirror from GitHub to GitLab

As of 2021 sadly it has become a "Premium" feature of GitLab to mirror data from another repository.

A possible workaround is to add an additional origin and push to both GltHub and Gitlab:

git remote set-url --add origin git@github.com:<username>/<project>.git

Or:
git remote add github git@github.com:<username>/<project>.git
git remote add gitlab git@gitlab.com:<username>/<project>.git

Check with:
git remote -v

Then push to one specific or all:
git push github
git push gitlab
git push

https://9to5answer.com/mirroring-from-gitlab-to-github
https://stackoverflow.com/questions/11690709/can-a-project-have-multiple-origins

GitLab project description and picture


To set an image for the project, go to project settings, General project settings and fill in the description, in the Avatar file field select the image and upload it.


Rebase navigation when solving conflicts


To find out how many commits that are left to rebase and maybe solve conflicts on, use git log <current branch name> and find the commit that failed - this one is noted both in the conflict details and in the end of the sections in the files that need to be changed. Then count the commits above it, note that not all may fail.

Regarding the syntax of these sections:

<<<<< HEAD
The data here is the current data.
======
The data here is the incoming data that failed to merge.
>>>>> Name of the incoming commit

Sometimes it may look like this - without any current data selected:

<<<<< HEAD
=====
Incoming data.
>>>>> Name of the incoming commit

This seems to mean that it failed to find the matching insertion start point in the current data. Check the incoming data, then go upwards and try to find where HEAD may fit, somewhere that the incoming data can be used as a replacement.

To solve a conflict, remove all the sections and only leave what should be left in the file. Then add the file with git add. When all are added, do git rebase --continue. If it says there are nothing to be done, do git rebase --skip. To abort, do git rebase --abort.


Hooks


There are several hooks available, check the .git/hooks/ directory which contain samples of hooks.

To create a pre-commit hook, create a file in .git/hooks/pre-commit and fill it with the commands to run. The hook is executed with the repository root directory as the path. So commands like git add can be run as if you were standing in the root directory.


Git bash auto-completion / autocompletion

If you type git br and then type Tab then Bash should spell that out to git branch.

If not, ensure the Bash completion package is installed (in Debian):
apt-get install bash-completion


Golden Rule of Rebasing

"The golden rule of Rebasing is that we should never use git rebase on public branches. If other people are using the same branch then they may get confused by looking at the changes in Master branch after GIT rebasing.

Therefore, it is not recommended to do rebasing on a public branch that is also used by other collaborators."

Source: https://www.knowledgepowerhouse.com/what-is-the-golden-rule-of-rebasing-in-git/1952


Rename master branch to main


Git:
git pull
git branch -m master main
git push -u origin main

GitLab:
Go to the repository on GitLab, Settings, Repository, Branch defaults.
At Default branch click Expand, change Default branch from master to main, click Save changes.
At Protected branches, click Expand, in the Protected branch list remove master, add main using the form above if you like to.

Then run this to remove master branch:
git push origin --delete master

Source: https://bud.agency/rename-master-branch-main-git-gitlab/

Then on other hosts using the repository:
git branch -m master main
git fetch -p origin
git branch -u origin/main main
git remote set-head origin main

If master is left locally, remove it:
git branch -D master

Source: https://stackoverflow.com/questions/71951105/how-to-change-current-branch-in-git-from-master-to-main

After this you may have a remotes/origin/HEAD -> origin/main branch, this is normal.

"is not a branch, but a symbolic pointer (HEAD) to a branch. It references the default branch that will be checked out when you are cloning the remote repo."

It can be removed:
git remote set-head origin -d

Source: https://stackoverflow.com/questions/12613793/why-is-there-a-remotes-origin-head-origin-master-entry-in-my-git-branch-l

If you are mirroring GitLab to GitHub, you also need do to this:

GitLab:

Go to the repository, Settings, Repository, Mirroring repositories.

There will be an error in the mirroring list at the bottom:
13:push to mirror: git push: exit status 1, stderr: "To https://github.com/<username>/<project>.git\n ! [remote rejected] master (refusing to delete the current branch: refs/heads/master)\nerror: failed to push some refs to 'https://github.com/<username>/<project>.git'\n".

If not, click on the synchronization button, then reload the page after a while. The error shows that it has tried and sent main to GitHub, but failed to remove master.

GitHub:
Go to the repository, Settings, Branches, Default branch, click the arrows button, select main, click Update, click that you understand.

Go to the repository main page - click on the repository name, <n> branches, search for master, click the recycle bin button, click the X at the search to check that main is left.

GitLab:
Go to Go to the repository, Settings, Repository, Mirroring repositories again and click the synchronization button, reload the page after a while. The error should be cleared.


Make a normal Git repository a bare (shareable/remote) repository 


A normal repository cannot accept pushed changes. For that you need a bare repository, but does not have a so-called working tree which is the list of files. It only has the .git directory renamed to repository.git. That is why GitHub for example has URL:s like github.com/<owner>/<repository.git>.

The following will preserve the normal repository while creating a bare repository in the same directory and making git ignoring it in the normal repository. Both have the cake and eat it.

1. Start with a regular repository made with git init, for example:

	mkdir repo
	cd repo
	git init
	echo hello > file.txt
	git add .
	git commit -m 'Create repository.'

You now have a regular git repository with 1 commit. The files in the directory except the .git directory are the "working tree".

2. Add the not yet created repo.git directory to .gitignore and commit the changes:

	echo "repo.git" >> .gitignore
	git add .
	git commit -m 'Update .gitignore.'

3. Copy .git to the new "bare" repository directory repo.git:

	cp -R .git repo.git

4. Configure the copied repository directory to be bare:

	git --git-dir=repo.git config core.bare true

Not doing this results in "remote: error: refusing to update checked out branch: refs/heads/main" when trying to push commits.

5. Set the normal/local directory origin to the bare repository in the same directory using a file path as the origin URL:

	git remote add origin ./repo.git
	git fetch origin
	git branch --set-upstream-to=origin/main main

The directory structure now looks like this:

	file.txt
	.git
	.gitignore
	repo.git

You now have 2 repositories in this directory, the normal one with file.txt, .git and .gitignore and the bare one with repo.git.

6. Make a new commit in your normal repository and push it:

	echo "hello again" >> file.txt
	git add .
	git commit -m 'Commit from original repository.'
	git push

7. Get out of the repository and make a clone:

	cd ..
	mkdir clone
	cd clone
	git clone ../repo/repo.git
	cd repo
	git pull

8. Make a commit from the clone and push it:

	echo "and hello again" >> file.txt
	git add .
	git commit -m 'Commit from clone.'
	git push

9. Check that it is in the original repository:

	cd ..
	cd repo
	git pull
	git log

If you want to clone your repository on another host you can do this:

	git clone user@hostname:/path/to/repo/repo.git

Reference: https://stackoverflow.com/questions/2199897/how-to-convert-a-normal-git-repository-to-a-bare-one

This is a personal note. Last updated: 2024-04-07 17:59:43.



GitHub

My

GitLab

My

LinkedIn

My

Klebe.se

Don't forget to pay my friend a visit too. Joakim