Needs to be revised and reduced more.
I’m glad if parts of it are helpful for others, but that’s not its raison d’Γͺtre:
It’s primarily meant to be my personal Git (Reference) cheatsheet/knowledge base,
i.e. a collection of notes for myself on how to use Git!
(These tipps were orignally based on my older notes in a text file on my PC, from around 2020-2022…)
(And by the way: I’m (still) using primarily Microsoft Windows.)
It is not meant as a general introduction or comprehensive reference for this tool. For that, more helpful and more general documentation is available on the net; for example:
- Official online version of the book Pro Git (2nd Edition, 2014), written by Scott Chacon and Ben Straub..
- (short) YouTube videos about Git from Philomatics.
Installation & Setup
Although I’ve installed Git many times by now, the time span between each occasion is significant enough that I forget the choices I made the last time, which makes me stumble the next time: “Hm, what do I usually pick here?” π€ (usually it needs only to be done for a new machine/installation every couple of years).
And while the setup its not too complicated, it would be helpful to have a brief reminder; thus this section now (on 2025-11-01, for Git version 2.51.2.windows.1).
-
Get Git for Windows:
Standalone Installer: Git for Windows/x64 Setup -
The Installation Wizard will show a few (multiple choice) dialogues, e.g. for selecting components.
I stick mostly with the default, but at some junctions, I make some adjustments.
Only noteworthy decisions are documented here!- On “β Windows Explorer integration”: Uncheck “β Open Git Bash here”
- Uncheck “β Associante .sh files to be run with Bash”
- Default editor: Change the default (“Vim”) and switch either to “Notepad++” or “Select other editor as Git’s default editor” (e.g.
C:\Program Files\Microsoft Edit\edit.exe). - On “Name of initial branch”: Keep the default (“Let Git decide”), which is currently still set to “Master”.
- On “Choosing SSH exe”: If already installed: Choose PuTTY’s plink.exe.
Otherwise choose “Use bundled OpenSSH” and change it later to PuTTY’s plink.exe - On “Line endings”: Keep the default: “Checkoput windows-style, commit unix-style” (
core.autocrlf = true) - On “Terminal emulator”: Change it to “β Use Windows’ default console window”
- On “Credential helper”: Change it to “β None”
But regardless what one chooses here: It can be changed again, anyways by the ways of Git configuration…
Configuration
Configuration files
Git provides three different scopes for storing configuration data.
And probably just to make life more complicated than neccessary, the configuration files are named differently in each scope…
Furthermore, Windows Git config files are each stored in different locations.
| Order | Scope | Filename | Location (under Windows) |
|---|---|---|---|
| 1 | System | gitconfig |
Program folder (e.g. C:\Program Files\Git\mingw64\etc\gitconfig). |
| 2 | Global | .gitconfig |
User’s local profile or home directory (e.g. C:\Users\Sascha\.gitconfig). |
| 3 | Local | config |
Inside the hidden .git directory of the repository. |
The scopes are cascading, so the system scope trumps the global scope; and the global scope trumps the local scope:
( system ( global ( local ) ) )
The global Git configuration file (.gitconfig) will only be created the first time it is used.
Even just asking Git to edit the file will force its creation:
git config --global --edit
To get a list of all settings; apply --show-origin to also show in which file each value is set; type q to exit:
git config --list
git config --list --show-origin
To get only the current value of a specific key, use git config <key>.
For example:
git config user.name
- Note:
- Git configuration variables can’t be set by the repository you are cloning, to prevent the execution of arbitrary code.
Basic Setup
To reset any config item back to is default value, simply use --unset; for example:
git config --global --unset user.name
User identity
git config --global user.name "Sascha Offe"
git config --global user.email "id@example.net"
Text editor
In the following example, it’s set to use Notepad++ (see also Command Line Options):
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
By the way: To use the classic/native(?) backslash-path-separator (\), you’ll need to escape it with another backslash: \\
Example: "C:\\Program Files\\Notepad++\\notepad++.exe" -multiInst -notabbar -nosession -noPlugin
Alternative: Microsoft recently released Edit, a new and Open Source text editor for the terminal; with a TUI inspired by the old MS-DOS 5.0 Editor (of which I have very fond memories). I’ll try this one out for a while:
git config --global core.editor "`"C:/Program Files/Microsoft Edit/edit.exe`""
And another tip: If you want/need quotation marks (due to spaces in the path): Escape them (in Powershell!) with the backtick symbol:
Example: git config --global core.editor "`"C:/Program Files/Microsoft Edit/edit.exe`""
Ignore items in all repositories
If you always want to ignore the same kind of files and folders,
you can define a global ignore file that will be applied to all repositories on your system (next to the local,
repo-specific .gitignore file).
The file and its content must be created in the same manner, but name and location is up to you.
I prefer something like .gitignore_global and save it (for maintainability reasons) in one of my repositories.
git config --global core.excludesfile C:\<path>\.gitignore_global
Default branch name
By default Git will create a branch called master when you create a new repository with git init.
From Git version 2.28 onwards, you can set a different name for the initial branch.
In the following example, it’s set to name it main:
git config --global init.defaultBranch main
Aliases
You can create aliases (to shorten or customize common actions), which then can be invoked by
git <Alias>
For examle: Define slog as an alias for calling log with specific parameters:
Setup an alias for a Git command (for example to provide certain options by default, e.g. always using ISO 8601 based timestamps in log output).
git config --global alias.slog log
That will add an entry under the alias section in the global .gitconfig file, which you can further refine
by opening the configuration file in a text editor – git config --global --edit – and then find the
section there; for example:
[alias]
slog = log --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=iso
More ideas:
git config --global alias.c commit
git config --global alias.co checkout
git config --global alias.st status
GUI Tools
Despite the fact that my main motivation for this cheatsheet is to have a collection of often-used native Git commands for the Command Line Interface (CLI) at hand, and idea of not being reliant on other (graphical, external/third-party tools, that may change or disappear), it is sometimes, for some tasks, a good idea to use a GUI.
-
git gui: A portable graphical interface, included with Git:
git gui
Enables a user to make changes to a repository (new commits, amending commits, creating branches, local merges, fetching/pushing to remote repositories, etc.). Has also menu actions that start a gitk session. -
gitk: A repository browser, included with Git:
gitk
Shows branches, commit history and file differences. It’s the utility started by git gui’s Repository Visualize actions. -
Git Extensions (Github)
A standalone UI tool for managing git repositories that also integrates with Windows Explorer and Microsoft Visual Studio.
Git Repository
The git init command creates a new, fully functional, version controlled repository; Git doesn’t require any pre-existing server or admin privileges.
Some terminology clarification before we continue:
-
- “Repository”
- Essentially the (hidden)
.gitfolder inside the workspace.
-
- “Workspace | Working Directory | Working Tree | Worktree | Working Copy”
- Essentially synonyms for the project folder itself, in which one is working with the source code (actively editing and updating the files that Git should track).
A Git repository comes in two different flavours (nice comparison/description):
- Normal repository β for working
- A normal
git initcreates everything you need to support a full-featured, Git-based environment, along with a special spot known as the working tree (aka working directory), where you can create files and write code.Main points:
- The files and folders at the top/root level represent the working tree/directory (where a developer actively edits and updates files that Git tracks).
- The hidden
.gitdirectory in the top/root level contains the Git meta-data for this repository (e.g. the history of all commits across all branches).
- Bare repository β for sharing
-
If you only want to host/manage a Git repository (similar to what GitHub, BitBucket, GitLab etc. offer), you create a bare Git repository with
git init --bare.A bare Git repository has all the capabilities of a normal (non-bare) repository, with the exception that it can’t be used to work in it:
It is intended to be used as a remote repository, where code is shared (between members of a team), but it’s not intended for local development!
Users can push to and pull from it, but can’t use it for ongoing development (local commits, branch creation, etc.); for that, a normal repo with a workspace is needed.If you inspect a bare Git repo, you’ll notice that it’s missing the (hidden)
.gitfolder of a normal repository. Instead, all that meta-data content is right there in the root directory (with some differences between both repo types, but that’s not important now).Main points:
- Contains only the Git meta-data itself at the root level (in a normal Git repository stored in a hidden .git subdirectory).
- Doesn’t have a working tree (and can’t have a working tree).
- Doesn’t have a default remote origin repository: Git assumes that it will serve as the origin repository for remote users, so it doesn’t create a default remote origin (= pull and push operations won’t work here, since Git assumes that you don’t intend to commit any changes directly into this repository).
- Typically used as a central place for exchanging data with others (by pushing to and pulling/fetching from it).
- By convention(!), the name has usually a
*.gitsuffix (e.g.<ProjectName>.git).
A brief comparison of the file structure of both repo types:
| Initialized empty normal Git repository | Initialized empty bare Git repository |
|---|---|
The |
|
Create a bare repository
The most common use case for a bare repository is to create a remote central repository.
Central repositories should always be created as bare repositories, because pushing branches to a non-bare repository has the potential to overwrite changes.
Think of it as a way to mark a repository as a storage facility, as opposed to a development environment.
This means that for virtually all Git workflows, the central repository is bare, and developers local repositories are non-bare.
git init --bare [<directory>]
The --bare flag creates a repository that does not have a working directory, which makes it impossible to edit files and
commit changes in that repository.
You would create a bare repository to push and pull from other repositories, but never directly commit to it.
By convention, the name of repositories initialized with the --bare flag should end with .git:
git init --bare MyProject.git
[TODO 1]
Note that in this case you’ll need to first allow people to push to your repository. When inside test_repo.git, do
git config receive.denyCurrentBranch ignoreAs commented by prasanthv, this is what you want if you are doing this at work, rather than for a private home project.
git init --bare --shared=groupYou can also add the –shared option for init if you plan on having other people push to this repo. It automatically adds group write permissions to the repository
[TODO 2]
Create a bare repo (ie
git init --bare MyProject.git) on the network drive (if not already have done that).Add the new bare repo as a remote repo to your project repo (of you not already have done that, ie
git remote add origin <path to bare repo>)and push all commits to the new remote repo (ie
git push --mirror origin).On the other computor you can now clone the new remote bare repo from the network drive (ie
git clone <path to bare repo>)
git remote add origin //remoteServer/git/Share/Folder/Path/MyGitRepo1 git push origin master
Create a local repository
“Creating a new local repo” simply means applying the init command, so that a hidden .git subdirectory will be generated by and for Git.
No files or directories will be tracked by Git by default!
git init [<directory>]
This adds a .git subdirectory to the current or the specified directory and makes it possible to start recording revisions of the project.
(Running git init on a directory that already contains a .git subdirectory is harmless:
It will not override an existing .git configuration.)
-
Variant A: Create a Git repository as a sub-directory of the current directory:
C:\> git init RepoName C:\> cd RepoName C:\RepoName> -
Variant B: Use an (empty) directory and then create the repository therein:
C:\> cd RepoName C:\RepoName> git init
This is now the checkout (or working copy) of the repo.
Its content can be either untracked (default) or tracked by Git.
More…
- https://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/
- https://git-scm.com/docs/gitrepository-layout/
- https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-init
Clone a Git Repository
Clone a repository, in either a new subdirectory (named like the original repository);
or into a specfic directory (supplied by name or path):
TODO - Using use . for the current working for “Path\to\a\RepoCloneDir”
- Via SSH (Example: From BitBucket.org):
git clone xxx@yyyyyyyyy.zzz:abc/<RepoName>.git [Path\To\Local\RepoCloneDir] git clone git@bitbucket.org:<username>/<RepoName>.git [Path\To\Local\RepoCloneDir]- Via HTTPS:
git clone https://yyyyyyyyy.zzz/abc/<RepoName>.git [Path\To\Local\RepoCloneDir]
Only a specific tag or branch
As above, but with the parameter branch specify, which branch (or tag) you only want to get:
git clone --branch <tag|branch> [... as usual ...]
Shallow clone (limited history)
Clone the repository from Repo_URL, but only with the commit history specified by the option depth.
Shallow cloning is useful when one is working with a huge repository that has an extensive commit history, but of which you don’t need all of right now.
In this example, only the most recent commits (depth level 1; --depth=1) are included in the new clone:
git clone --depth=<level> <Repo_URL>
Information about/from a Git Repository
Other commands ([TODO] not yet mentioned below):
git log --graph --decorate --pretty=oneline --abbrev-commit --all
git branch
git tag
General infos
For example the Fetch- and Push-URL, the branch name, …:
git remote show origin
Status
git status
git status -s | --short
Differences (changes/modifications) in files
git diff
git diff --staged
Commit Log
By default, git log shows the commits made in that repository in reverse chronological order (i.e. the most recent commits first).
The order can be switched with --reverse, but one can’t simply combine it with -n 3 to only show the first three commits.
git log -n 3 # Show the latest three commits
git log -3 # Same
git slog -3 # Same, but in short form (single line)
Latest Git commit from a branch
git log -n 1 # Current branch
git log -n 1 origin/master
git log -n 1 some_local_branch
git log -n 1 --pretty=format:"%H" # Only the hash value of the commit
Source: Command to get latest Git commit hash from a branch (StackOverflow, 2013)
Pretty Format
More on Git Log: Pretty Formats
| x | y |
|---|---|
%h |
abbreviated commit hash |
%x09 |
tab (character for code 9) |
%an |
author name |
%ad |
author date (format: respects the --date= option) |
%s |
subject |
| (file) | There is no placeholder for the filename; workarounds: Use --name-only or --name-status or --stat(but that won’t be on a single line!) |
> git log -n 1 --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=iso
501644b Sascha Offe 2025-06-09 19:49:25 +0200 Minor tweak
> git log -n 2 --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=iso --name-only
65a3fbe Sascha Offe 2025-11-01 21:31:27 +0100 Improvements regarding the parameters for and the handling of colors
powershell/Modules/saoe/public/Miscellaneous/Write-saoeHost.ps1
0bbfc39 Sascha Offe 2025-10-31 21:43:06 +0100 Custom version of Write-Host with more font & color styling capabilities
powershell/Modules/saoe/public/Miscellaneous/Write-saoeHost.ps1
> git log --stat --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=iso
d5d24c9 Sascha Offe 2025-10-26 14:25:17 +0100 Updates because the URL of the remote Git repository changed
content/blog/hotkey-1.0.md | 7 ++-----
content/blog/journal-11.md | 4 ++--
content/blog/journal-18.md | 39 +++++++++++++++++++++++++++++++++++----
content/page/software-overview.md | 20 ++++++++++----------
4 files changed, 49 insertions(+), 21 deletions(-)
...
> git log --graph --decorate --oneline
* 81479d0 (HEAD -> master, origin/master, origin/HEAD) Latest commit message...
* 64fbc25 Previous commit message...
...
Example (Powershell Gridview)
This example uses the slog alias (see above) to get short log lines; those will be converted to CSV objects and then handed over to Out-Gridview for displaying it in a window:
git --no-pager slog | ConvertFrom-Csv -Delimiter "`t" -Header "Short Hash","Author","Timestamp","Subject" | Out-GridView -Title "Git Log"
Commits between X and Y
Where X and Y can be a tag, HEAD or a Commit ID.
X and Y must be in ascending order, i.e. <older>..<newer> – the other way around doesn’t work!
git log --pretty="%h (%an) - %s" <tag-name>..HEAD
git log --pretty="%h (%an) - %s" c3eeab6..0158d99
Regarding double dots (..) and triple dots (...)
(it’s complicated:
StackOverflow #1,
StackOverflow #2
:-/):
..indicates a range....gives the symmetric difference (only showing commits not reachable from both tags).
Commits for a specific date range
git log --since='<date>' --until='<date>'
git log --since='<date>'
git log --until='<date>'
The <date> value can be specified in a variety of formats, like 2025-07-11 or 07/11/2025 or Jul 7 2025;
even relative terms are possible, for example yesterday or 2 weeks ago etc.
Gotcha: Stuck in the CLI when using git log
Git Windows Command Prompt gets stuck during Git commands with (END),
for example when using git log.
The reason is the use of the unix-y pager command “less” under Windows.
Workaround: Press q to exit the pager.
git --no-pager|-P: Don’t pipe Git output into a pager (a “pager” is something like less or more, which is a bit strange to use on Windows).
Other alternatives to handle the Log: Pipleine the unpaged output to some Powershell cmdlets:
git --no-pager log ... | more
git --no-pager log ... | Out-Host -Paging
git --no-pager log ... | Set-Clipboard
git --no-pager log ... | Out-GridView
Who is responsible? (Who is to blame?)
git blame shows what revision and author last modified each line of a file; has multiple optional parameters to tweak the output.
> git blame .\ReadMe.md
e1b5357b (Sascha Offe 2024-03-10 18:15:12 +0100 1) # Powershell module [...]
0bdc6575 (Sascha Offe 2020-12-29 20:58:38 +0100 2)
476c3e37 (Sascha Offe 2021-01-16 17:34:02 +0100 3) My personal toolkit [...]
...
Forward: <Space>
Exit: q
Add changes to the staging area (index) / Track items
Update the index with the content found in the working tree (prepare/stage the content for the next commit). Directories will be added just like that, including all subdirectories and files in it.
The primary function of the git add command is to promote pending changes in the repo’s working directory to the Git staging area.
By adding items to the index, these item will also change from being untracked to being tracked by Git.
By the way, the options are case sensitive! (I’m looking at you, -A).
git add [options] <file|directory> [<file|directory>] [...]
git add file1.ext file2.ext file3.ext
git add *.x
git add */*.x # [TODO] What?!
Example: Three versions that all do the same:
- Add everything (all changes) to the staging area, even yet untracked files & folders (empty directories will be ignored!).
- Add (recursively!) all changes to the staging area;
--allalso modifies/removes items to match the working tree! - Note:
git add -A(and-u) (i.e. without a path) operate on the entire working directory tree!git add . git add --all git add -A
Useful options
| Short | Long | Description |
|---|---|---|
-A |
--all |
Adds, modifies, and removes index entries to match the working tree (including new, previously untracked files in sub-directories!). |
-n |
--dry-run |
Don’t actually add the file(s), just show if they exist and/or will be ignored. |
-v |
--verbose |
Verbose output. |
-e |
--edit |
Start the editor and show changes in unified diff format. |
-f |
--force |
Allow adding otherwise ignored files. |
-u |
--update |
(see below/TODO) |
-i |
--interactive |
(see below) |
Interactive Staging: git add -i
-
You can commit just part of a change to a file.
So if you notice a small problem and already have a bunch of changes made, you can still make those changes, and commit them separately.
I don’t use it often and find it’s kind of painful to use, but if you’re in the position where you’ve already saved two different things in your IDE and need to pull them apart for commit, it’s a useful tool.
[TODO] -u/–update
Update the index just where it already has an entry matching pathspec. This removes as well as modifies index entries to match the working tree, but adds no new files.
If no pathspec is given when -u option is used, all tracked files in the entire working tree are updated (old versions of Git …).
Remove and modify index entries to match the working tree, but does not add new files!
…
Add/delete only all tracked modified files to the stage; ignore all yet untracked modified files.
Commit staged changes to the repository
Commit the staged files to the local repository:
git commit -m "Message for the initial commit"
On Commit Messages
Mood & Tense
I was aware, that the common and recommend way of writing commit messages was and is to use to use the imperative mood,
in present tense; like “Do X”.
(Tip: Read your commit message with this at the beginning: “If applied, this commit will <do x…>”
But that always felt somewhat wrong to me when typing, probably because I always used version control systems alone, and on codebases, where I am the single developer.
And thus commiting a change happens normally at the end of my develeopment process, when I have already written all the code and comments – so I treat it more like a worklog of what I did do or did accomplish in the hours or days before. For that, the indicative mood in past tense makes more sense.
But I also know that Git originally comes from the world of distributed and decentralized development, by many programmers: The Linux kernel.
On the one hand: These are different circumstances, unlike mine. Why should I care?
On the other hand: After having read now a few more articles and discussions (pro & contra) about this topic (see below), I’m actually sligthly more in favor of imperative, present tense mood…
And also: This is for the subject line; the body of a commit message can be different
Food for thoughts:
- Git Commits: Past or Imperative?
- Imperative Git commit messages in the active tense or mood
- How to Write a Git Commit Message (5. Use the imperative mood in the subject line)
- Reddit: In what tense do you write your commit messages?
- Reddit: Is it bad practice to use past tense in commit messages?
- Hacker News: A Note About Git Commit Messages (tbaggery.com)
- Stack Overflow: Should I use past or present tense in git commit messages? [closed]
Ignore files & folders
Repository scope
Some files and directories should intentionally be ignored by Git and remain untracked (files that are already tracked by Git are not affected):
-
Create the
.gitignorefile (in the repository directory).New-Item -ItemType File -Name .gitignore # Generating a 'dot' file on Windows it easier with Powershell. attrib +h .gitignore # Hide file in the normal file explorer view. -
Create rules in that file for what should be ignored:
(Each line in a.gitignorefile specifies a pattern)#starts a comment line.- Folders must have a trailing slash:
build/(this will ignore a directory with the name “build” anywhere in the file tree). *build*/ignores all kinds of “build” folders, e.g. “build”, “build32”, “build64”, “_build”, “foo/build”, etc.
File content example:
# Ignore all kinds of 'build' folders (build, build32, build64, _build, foo/build, etc.): *build*/ # Ignore this file anywhere at or below the directory that contains this .gitignore file: CMakeUserPresets.json # Ignore byte-compiled/optimized/DLL Python files __pycache__/ *.py[cod] *$py.class -
Add and commit this file to the repo, like any regular file.
(Because a.gitignorefile is not added to a repository by default!)git add .gitignore git commit -m "Add .gitignore file to the repo"
Global scope
If you’re is working across multiple projects, there are often files and folders that should always be ignored,
(i.e. these rules should apply to all repositories on the system).
For that, one can use a global .gitignore file, instead of adding the patterns to each repository’s local .gitignore file individually.
It’s also set up in the same way (see above), but one must point the Git configuration to that file.
Commit change to the staging area/index
1. git add
2. git commit -m "Message"
or in one step
(But new files that are still untracked will be ignored; those need to be explicitly added first!)
git commit -am "Message"
git commit -a # Opens an external text editor for the commit message.
“… as a convenient way of reviewing the changes I am about to commit.
With that, only committing part of the changes is no additional effort.
git commit --patch
git add --patch # **[???]**
Amend change
This will let you add changes to your latest commit & even edit the commit [history] message
If you’ve missed to mention a thing, or forgotten a minor change in a source code file, you can add it retroactively to the latest/most recent commit, before it has been pushed!: (I’m not sure if it’s not technical feasible or not, but at least it’s not recommende to amend a commit that has already been pushed…)
git commit --amend # Variant A
git commit -a --amend # Variant B
That opens an external text editor which is prefilled with the most recent commit message. Variant (A) requires that the change has been staged already; use variant (B) to add the lates modification to the stage in one go.
Options:
git commit -a --amend --no-edit
-a: Automatically add all current changes--no-edit: Don’t open the editor to edit the commit message
- ! Careful: Don’t amend commits that have already been pushed, because it modifies the commit history!
- One could do it if one works alone or when you’re absolutely sure that nobody has pulled your commit yet.
But even then, you’ll have to usegit push --forceto overwrite your old, un-amended commit!
Even safer:git push --force-with-lease --force-if-included: This will abort if there are any new changes in the remote repo; this avoids that another one’s pushed commits will be deleted
Undo & Redo stuff
Unstage/Untrack a file
git reset HEAD <file>
git reset -- <file> - Removes file from the stage/index.
Undo the last commit
Go back to the previous state (HEAD-1).
Soft Reset: Files will remain, uncommited.
git reset --soft HEAD~1
Hard Reset: All files will be deleted:
If you have commited file1, file2 and file3, all three will be deleted from the working directory!
git reset --hard HEAD~1
Remove a file or directory
Remove a File:
1. git rm file_name # Remove from local repository and also from working directory
1. git rm --cached file_name # Remove from local repository, but keep copy in the working directory (= untracked file)
Remove a directory:
- Non-Empty directories must be deleted recursively (
-r; all content), else this command will fail. - Empty directories can’t/don’t need to be removed by Git, because they don’t exist from Git’s view of the world. Trying to do so results in an error: fatal: pathspec ‘…’ did not match any files. Git only tracks/cares for files dsd
1. git rm --cached -r directory_name
2. git commit -m "Remove ..."
3. git push origin branch_name
Note: To remove sensitive data completely, even if already published, one will have to do some special magic (rewriting commit history etc.); look it up if needed (hint: git filter-branch -f –index-filter ‘git rm –cached –ignore-unmatch file.txt’; git forget-blob…) more.
But even if done, it’s highly recommended to change that data (like passwords, SSH keys etc.), since you will never know if it has survived in some out dated clone or fork on someone’s machine!
Reset file to original state (discard latest modifications)
(?) Moves file from the stage (index) back into the working directory.
git checkout -- <FileName>
git checkout HEAD -- <FileName>
Rename or move a file or folder
To preserve Git history, use git mv instead of the OS methods for moving or renaming files.
Because otherwise, Git just sees a deleted file (the old one) and a brand-new file (the new one).
-
Example: (Git has some ways to auto-detect whether the old and new name (or path) may be the same item, one should bet on it…) Update: Hm, maybe it’s not so smart and
git mvis just a shorthand -> https://stackoverflow.com/questions/1094269/whats-the-purpose-of-git-mvgit mv OldName NewName (The files are automatically added to the stage; no need to run `git add`!) git commit -m "Message..." -
Example: Move all files from a subdirectory up one level (to the current directory):
Using a workaround for Windows, when using Powershellgit mv (gci .\NetInstall\*) .
Restore working tree files
git restore path/to/file
git restore --staged path/to/file
Sharing and Updating
Push to Remote Repository
Pushes the currently checked-out branch to the origin (remote).
git push <remote> <branch>
git push # without any arguments
So, if git status said you were in the master branch, and git remote -v returned the remote origin, then git push would be the same as git push origin master.
(git push alone has supposedly been deprecated for some time, because it is implicit, rather than explicit.)
When pushing on the same branch, one can also use instead:
git push <remote> HEAD
Add a remote with the name “origin”:
git remote add origin git@bitbucket.org:<username>/<RepoNameOnBitBucket>.git
git push - If a remote (e.g. BitBucket) was set up; see above.
git push origin branch_name - ... or explicitly call the remote and branch by name.
Pull or Fetch from Remote Repository
-
Pull means: Both the local Git repository and the working directory will be updated with the latest changes from a remote repository (only applicable if there are no uncommitted files in the workspace).
Sidenote:
git pullis actually a combination of the two commandsgit fetch(download remote commits) andgit merge(merge local and remote commits).After you’ve pulled the changes…
- The local Git repo will now be in sync with the remote repo.
- The local filesystem (workspace) will then have the latest, up-to-date items.
This command has one prerequisite: The user cannot be actively editing any tracked files in their local workspace that conflict with what’s on the remote server:
If Git notices any conflicting files in the workspace, it aborts the task of updating the workspace and only updates the local Git repo.git pull -
Fetch means: Only the local repository will be updated with the latest changes from a remote repository; the working directory will not be changed at this time (one needs to merge later, see below).
With a fetch, you can finish editing files locally in the working directory, before you then commit these changes and merge them to synchronize these updates with the fetched files. This brings you up to date with the updates the fetch pulled down from the remote machine.
The fact that the merge is a distinct action/step gives you more control about how and what exactly should happen:
- a normal two-way-merge (side-effect: creates an extra merge commit)?
- a rebase (side-effect: rewrites history)?
When no remote is specified, by default the “origin” remote will be used (unless there’s an upstream branch configured for the current branch):
git fetch
An aborted pull is a fetch
If you try to do a git pull operation, but your working directory has uncommitted files, or a copy of the remote files into your workspace would create a merge conflict, the git pull operation short-circuits and turns into a git fetch operation instead.
All of the updates from the remote repository are copied into your local Git repository, but the system leaves your local workspace alone.
This emphasizes the fact that the git pull is really two operations combined into one: the git fetch and the git merge commands. If a developer successfully issues a git fetch and a git merge command right after one another, the result is equivalent to a git pull.
[TODO] https://www.atlassian.com/git/tutorials/syncing/git-pull
[TODO] On Pull & Rebase
-
Initial situation:
(RemoteRepo) \ [OtherDev pushed before me into the Repo] | B C | | A A [I] [OtherDev] -
Now I want to push my changes also to the repo… That will be rejected, because I didn’t yet take into account the last changes of OtherDev:
I do: git commit -am "foo" git push Repo says: Rejected! -
What to do now? If I’d do just a
git pull, I would create a new Merge Commit:_ (RemoteRepo) / D } <-------------- merge commit "git pull / | } +---> C B } My Commit \ | } \_ A } -
Therefore, do this instead:
git pull --rebaseDesired state: That makes a "rebase": (RemoteRepo) B Put aside 'B', Holt 'C' | Get 'C' from the Repo and add it; +--> C only after this 'B' will be attached to 'C'. | A
Summary:
- Always try first with
git pull --rebase. If that works: Great, you’re done! - Else (if you get merge conflicts): Abort & undo everything by using
git rebase --abort - Pull normal (and resolve merge conflicts):
git pull { resolve merge conflicts } { ... or do an interactive rebase [advanced] }
Tip: Alias: “git pr” -> “pull –rebase”
Branching and Merging
Branches
List branches
git branch # List only local branches
git branch -r # List remote branches
git branch -a # --all (?) List all branches (local & remote)
Create new local branch, but stay in the currently checked out (e.g. master)
git branch <NewBranch>
git branch <NewBranch> [<StartingPoint>]
Create new local branch and switch to it immediately
git checkout -b <NewBranch>
Switch branch
git checkout <BranchName>
Push a new local branch to a remote Git repository and track it too
- (Create branch, see above)
git push -u origin <BranchName>
Delete (close) branch
git branch -d <BranchToBeDeleted> : The branch must be fully merged in its upstream branch,
--delete or in HEAD if no upstream was set with --track or --set-upstream-to.
-D : Force delete the specified branch, even if it has unmerged changes. Shortcut for --delete --force.
Delete (close) branch locally
git branch --delete localBranchName
Delete (close) branch remotely
git push origin --delete remoteBranchName
Then try to synchronize your branch list using:
git fetch -p
The -p flag means “prune”. After fetching, branches which no longer exist on the remote will be deleted.
Merge
-
Checkout the branch to which the branch should be merged, e.g. ‘master’:
git checkout master -
Merge:
git merge Branch123 -m "Merged Branch123 to master." -
Might result in a conflict.
The affected file in the working directory has now some markers:<<<<<<< HEAD Different in Head ======= something completely different in BranchToBeMerged >>>>>>> BranchToBeMerged -
Resolve manually:
Delete the conflict markers (<<<<<<<,=======,>>>>>>>) and make the changes you want in the final merge; save file.
Add file to stage again:git add <filename>(that marks the conflict as resolved).
Conclude the process by a regulargit commit(no need to rungit merge...again after that).
By the way: A (simple) merge isn’t really shown in any commit history, it seems. There are long explanaition on why/how Git works, but I haven’t delved into it.
Squash multiple commits into one with rebase
Do this on your feature branch. Only squash commits that haven’t been pushed to the repository (are not yet public): Squashing rewrites the history!
git rebase --interactive HEAD~<number_of_recent_commits_you_want_to_squash>
Example:
- Start interactive rebase mode to squash the latest three commits:
git rebase -i HEAD~3 - Editor opens: Make sure the first commit says pick (p) and change the rest to squash (s) (without a “pick”, Git complains that a commit has to happen).
- Save and close the editor.
- Editor opens: Edit commit message.
- Save and close the editor.
- Force push the final, squashed commit:
git push -f
Tags
Tags specify points in a repository’s history.
There are two types of tags: lightweight and annotated.
-
A lightweight tag is usually meant for private or temporary labels.
It’s just a pointer to a specific commit object, without any additional data.
If you callgit tagwith just the tag name (and no other option), a lightweight tag will be created.Just provide a tag name, but don’t supply any other options like
-a,-s, or-m:git tag v1.0.0-beta -
An annotated tag is usually meant for releases.
It’s stored as a full commit object in the Git database, with additional data:- Checksum π‘’ automatic
- Name and E-Mail-Address of the tagger π‘’ automatic
- Timestamp π‘’ automatic
- Message π‘’
-m - Optional: Signature and Verification with GNU Privacy Guard (GPG) π‘’
-s
If you call
git tagwith-a(annotatation),-m(message) or-s(sign), an annotated tag will be created.
The annotation/message is stored with the tag; if you omit-mhere, the editor will be launched.git tag -a v1.0.0 -m "The first release."
Sharing tags with the remote repo
By default, the git push command does not transfer tags to remote servers!
You need explicitly push tags to a shared server after you have created them:
git push <remote> <tagname>
If you have a lot of tags that you want to push up at once
(this will transfer all of your tags to the remote server that are not already there):
git push origin --tags
Now, when someone else clones or pulls from your repository, they will get all your tags as well.
Note: Pushing tags does not distinguish between lightweight and annotated tags; there is no simple option that allows you to select just one type for pushing.
Commit and tag in one command
That is not possible!
Do this instead:
git commit -m "Ready for v1" # Commit
git tag -a v1.0.0 # Tag (annotated)
git push # Push the commit to the remote repo
git push origin master --tags # Push the tags to the remote repo/branch
View & List tags
- See the tag data along with the commit that was tagged:
git show <tag> - List all tags in alphabetical order:
git tag - Search for tags that match a particular pattern:
git tag -l "v1.*"
Create a tag
- If one of
-a,-s, or-u <keyid>is passed, the command creates a tag object, and requires a tag message. - Unless
-m <msg>or-F <file>is given, an editor is started for the user to type in the tag message. - If
-m <msg>or-F <file>is given and-a,-s, and-u <keyid>are absent,-a(= create an Annotated Tag) is implied.
Otherwise, a tag reference that points directly at the given object (i.e., a lightweight tag) is created.
Create a tag later
You can also tag commits after you’ve moved past them.
Example: Suppose you forgot to tag the “Update CMake” commit (in the middle) as “v1.5”:
> git log --pretty=oneline
166ae0c4d3f420721acbb115cc33848dfcc2121a Create something
9fceb02d0ae598e95dc970b74767f19372d61af8 Update CMake
964f16d36dfccde844893cac5b347e7b3d44abbc Edit ToDo list
...
To tag that commit, you specify the commit checksum (or a part of it) at the end of the command.
In this example, the first seven characters from the beginning of the commit checksum (9fceb02) are unique enough to identify the commit without a doubt:
git tag -a <tag> <CommitChecksumPart>
git tag -a v1.5 9fceb02
You can then see that the commit is now tagged as “v1.5”:
> git show v1.5
tag v1.5
Tagger: Sascha Offe <id@example.net>
Date: ...
version 1.5
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Sascha Offe <id@example.net>
Date: ...
Update CMake
...
Delete a tag
To delete a tag on your local repository, you can use git tag -d <tag>.
Note that this does not remove the tag from any remote servers.
There are two common variations for deleting a tag from a remote server.
-
The more intuitive way to delete a remote tag is with
git push origin --delete <tag>. -
The other method is
git push <remote> :refs/tags/<tag>– interprete it as the null value before the colon being pushed to the remote tag name, effectively deleting it.
[???] What about deleting local and then pushing to remote? Does that not work?
Checking out a tag (instead of a branch)
If you want to view the versions of files a tag is pointing to, you can do a git checkout of that tag, although this puts your repository in “detached HEAD” state, which has some ill side effects!
git checkout <tagname>
In “detached HEAD” state, if you make changes and then create a commit, the tag will stay the same, but your new commit won’t belong to any branch and will be unreachable, except by the exact commit hash. Thus, if you need to make changes – say you’re fixing a bug on an older version, for instance – you generally should create a branch:
git checkout -b <new-branchname> <tagname>
If you do this and make a commit, your new-branchname branch will be slightly different than your tagname tag since it will move forward with your new changes, so be careful.
Hooks
Hooks are custom scripts that can invoked when certain events happen.
- Can be server-side hooks (for network events like push, etc.) or client-side hooks (for local/client events like commit, merge, branch, etc.).
- Location: The directory
.git/hooksin the local repository on the local client. - Hooks are not be managed/versioned along with the actual repository!
Hooks are local to a Git repository, and they are not copied over to the new repository when you clone a Git repo! - Since hooks are local, they can be altered by anybody with access to the repository.
This has an important impact when configuring hooks for a team of developers.- One needs to find a way to make sure hooks stay up-to-date amongst team members.
- One can’t force developers to create commits that look a certain way – one can only encourage them to do so.
- Or one points the local Git configuration to any different directory (since Git 2.9):
e.g.
git config --<Scope> core.hooksPath <Path>
The path can be absolute or relative; the new directory can be for example a version-controlled.
But: That must be done by each developer on its machine
(Git config variables can’t be set by the repository you are cloning, to prevent the execution of arbitrary code). - As an alternative, Git also provides a Template Directory mechanism that makes it easier to install hooks automatically.
Languages
Examples come often as Bash, Perl or Python scripts, but you can write a hook in any language,
as long as it’s executable on your box (i.e. can be invoked from the terminal/command line) –
see also
and also.
One could also use the hook script as a wrapper for calling another script.
(Incomplete) List of possible hooks
To enable a hook, just remove the “.sample” from the filename, or create a new file without the “.sample” suffix.
| Hook | Description |
|---|---|
| applypatch-msg | Allowed to edit the message file in place; can also be used to refuse the commit after inspecting the message file. |
| commit-msg | Called after the user enters a commit message. |
| fsmonitor-watchman | |
| post-update | |
| post-commit | Called immediately after the commit-msg hook |
| pre-applypatch | Can be used to inspect the current working tree and refuse to make a commit if it does not pass certain tests. |
| pre-commit | Executed every time you run git commit before Git asks the developer for a commit message or generates a commit object. |
| pre-merge-commit | Invoked after the merge has been carried out successfully and before obtaining the proposed commit log message to make a commit. |
| pre-push | Can be used to prevent a push from taking place. |
| pre-rebase | Can be used to prevent a branch from getting rebased. |
| pre-receive | |
| prepare-commit-msg | Called after the pre-commit hook to populate the text editor with a commit message. |
| push-to-checkout | |
| sendemail-validate | |
| update |
- Further reading:
How to…
Setup a SSH keypair on Windows to authenticate with your repositories
π How to set up a SSH key pair with PuTTY on Windows.
Import a local repository to a BitBucket repository
-
Create a new local Git repository (with some content/files maybe).
Example:C:\devel\git\> md RepoName C:\devel\git\> cd RepoName C:\devel\git\RepoName> git init C:\devel\git\RepoName> git add --all C:\devel\git\RepoName> git commit -m "Initial Commit" -
Logon to BitBucket.org and create there also an empty Git repository; that will become the remote/target.
(See also Importing code from an existing project) -
Connect your newly created local repository to the repo on Bitbucket (meaning: Add a remote with the name “origin”).
Get the clone URL from the BitBucket-Repo page; either SSH (e.g.
git@bitbucket.org:<username>/<RepoNameOnBitBucket>.git) or HTTPS (e.g.https://<username>@bitbucket.org/<username>/<RepoNameOnBitBucket>.git)I prefer SSH (it’s easier to work with, when PuTTY/Pageant is set up correctly):
git remote add origin git@bitbucket.org:<username>/<RepoNameOnBitBucket>.git -
Push local data to remote repository
(-u: “For every branch that is up to date or successfully pushed, add upstream (tracking) reference […]”)git push -u origin mainAssuming that the initial work for using a SSH key is done (see above), there still may show up warning/error messages (see below](#other-known-issues))…
-
Even if all that worked, you may still get another error:
! [rejected] main -> main (fetch first) error: failed to push some refs to 'bitbucket.org:<username>/<RepoNameOnBitBucket>.git' hint: Updates were rejected because the remote contains work that you do not hint: have locally. This is usually caused by another repository pushing to hint: the same ref. If you want to integrate the remote changes, use hint: 'git pull' before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.But the recommend simple “pull” will not help:
> git pull warning: no common commits ... There is no tracking information for the current branch.Solution: Since the local repo and the repo on BitBucket don’t have a shared history (yet), this must be explicitly allowed:
> git pull origin main --allow-unrelated-historiesThis will trigger an automatic merge action with default commit message – simply accept/use/do that!
Other known issues
-
On the first try, you may get a warning message like this:
The authenticity of host 'bitbucket.org (104.192.143.1)' can't be established. RSA key fingerprint is 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40. Are you sure you want to continue connecting (yes/no)?Solution: Thay is a measure of precaution: Troubleshoot SSH issues
The first time you access Bitbucket using the SSH URL, your SSH client checks to see if the Bitbucket host is a known host.
If the host is not yet in your SSH known_hosts file, SSH asks for your permission to add the Bitbucket host to the list of known hosts; you can answer that with “yes”. -
After answering with “yes”, you may get an error:
_git@bitbucket.org: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists._Solution: Let the environment variable
GIT_SSHpoint to PuTTY’s plink.exe (e.g.C:\Program Files\PuTTY\plink.exe).Use either Windows GUI or command prompt (
setxwill set the environment variable permanently, not just for this session!):setx GIT_SSH "C:\Program Files\PuTTY\plink.exe"(Update: Running the Git-for-Windows-Setup again, I noticed that it asks for using PuTTY’s plink.exe and adjusting the
GIT_SSHenvironment variable; seems I overlooked it the first time…)
Move file from repo OR split parts of a repo
New (2025-11)
- Variant A
- Use git-filter-repo: A 3rd party tool/add-on/script collection for Git.
But also acknowledged/recommended by Git!
See also below: I used it already? - Variant B
git filter-branch-> not recommended anymore!foo/ bar/ baz/ xyz/ <-- We wanna split 'xyz' from the 'foo'-repo > git clone foo > git filter-branch --prune-empty --subdirectory-filter xyz/ -- master ^^ a separator-plus-space! Not an argument!Rewrites the history of all commits, as if only ‘xyz’ ever existed.
The content of ‘xyz/’ move up!
And…? That’s it?!- Variant C
-
git subtree split --prefix=<path>/<folder> -b <name>
Creates a new branch “name” with the content of the prefixed folder ("path/folder”) -
git init --bare -
Back in the source repo: Push to the ‘master’ branch in the new repo:
git push ../new_repo ???? name/branch??? master -
Check
-
Remove from source repo:
git rm -r split_dir/ git commit -m "Remove..."
-
Move a file from one repository to another repository, with preserved Git history
Tested on my two test repositories on 2022-02-27 – Update 2025-11-17: Uh, I did use git-filter-repo already!?
-
Prerequisites
The third-party tool ‘git-filter-repo’ is required; it’s recommended by Git itself (instead of git’s own ‘filter-branch’).
Installation (Windows; run from a cmd shell, not from python!):
> python -m ensurepip --upgrade # If PIP is missing > python -m pip install --user git-filter-repo "WARNING: The script git-filter-repo.exe is installed in 'C:\Users\Sascha\AppData\Roaming\Python\Python39\Scripts' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location."So, add it to the path…
-
Clone the source repo
Clone the original source repo, because we will modify/rewrite history, so don’t use the orginal repo! And download the entire repository history:
C:\devel\git> git clone git@bitbucket.org:<username>/gittestrepo.git gittestrepo_clone C:\devel\git> cd gittestrepo_clone C:\devel\git\gittestrepo_clone> git pull --all --tagsTo be on the safe side, one could now detach this clone from its origin…
C:\devel\git\gittestrepo_clone> git remote -v C:\devel\git\gittestrepo_clone> git remote rm origin C:\devel\git\gittestrepo_clone> git remote -v… but ‘filter-repo’ will do that for you anyway. If you do it before yourself, ‘filter-repo’ will complain:
Aborting: Refusing to destructively overwrite repo history since this does not look like a fresh clone. (expected one remote, origin) Please operate on a fresh clone instead. If you want to proceed anyway, use --force. -
Filter out the files that should be moved
C:\devel\git\gittestrepo_clone> dir # For comparision (before/after) C:\devel\git\gittestrepo_clone> git filter-repo --path "file4.txt" C:\devel\git\gittestrepo_clone> dir # For comparision (before/after)One could also provide more paths in one go; example:
git filter-repo --path "path/to/file1" --path "path/to/file2" --path "dir1"Note that you’ll need to specify full paths to the files you want to keep; the ‘filter-branch’ solution used a grep hence the paths weren’t as relevant in that case.
What this does is goes through all commits in the clone of the original repository looking for files which don’t match the files you want to keep and removes their entries in the index.
Afterwards you’re left with just the commits for just the files you’re interested in (i.e. “file4.txt” or “path/to/file1”, “path/to/file2” and “dir1”).
Tipp: Normally, ‘filter-repo’ works by ignoring the filenames specified (they are, as the name suggests, filtered out). But if we want the inverse behavior, we want ‘filter-repo’ to ignore everything except the specified file. For that, pass
--invert-pathsas an additional argument. -
Clean up the clone repo
To make sure that everything is cleaned up, you can also run Git’s garbage collector explicitly, so that everything that isn’t required really has been purged:
C:\devel\git\gittestrepo_clone> git gc --aggressive-
Either put the file(s) in a brand new repo…
{ Now rename the directory to something more appropriate for the subproject that has been created and reassign the origin remote pointer (assuming, of course, that the remote bare repository has already been created):
git remote add origin git@git.server.example.com:new_repo_name.git
TO BE CONTINUED }
-
… or merge the file(s) and history to an existing repo
C:\devel\git\GitTestRepo2> git remote add templocal "C:\devel\git\gittestrepo_clone" C:\devel\git\GitTestRepo2> git fetch templocal C:\devel\git\GitTestRepo2> git merge templocal/master --allow-unrelated-histories C:\devel\git\GitTestRepo2> git remote rm templocal C:\devel\git\GitTestRepo2> git push
-
-
Remove the moved files from the original repo
Of course, the moved files need to be removed from the original repository (the real repo, not the clone) and a commit message should indicate where they ended up.
C:\devel\git\GitTestRepo2>cd .. C:\devel\git>cd GitTestRepo C:\devel\git\GitTestRepo>git rm file4.txt C:\devel\git\GitTestRepo>git commit -a -m "Moved to GitTestRepo2" C:\devel\git\GitTestRepo>git push
Split a repository in two (or integrate an old repository into a new one), with preserved Git history
This how I brought CLIOptions and InitFile into the newly created (local) repository Magpie (2021-02-11) Based on https://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/
# Create the new repository
C:> cd C:\devel\git
C:\devel\git> git init Magpie
C:\devel\git> cd Magpie
# Before we do a merge, we have to have an initial commit,
# so we'll make a dummy commit (for that, the repo cannot be completely empty)
dir > deleteme.txt
git add .
git commit -m "Initial dummy commit"
# Add a remote for and fetch the old repo
git remote add -f CLIOptions git@bitbucket.org:<username>/CLIOptions.git
# Merge the files from old_a/master into new/master
git merge CLIOptions/master --allow-unrelated-histories
# Clean up our dummy file because we don't need it any more
git rm .\deleteme.txt
git commit -m "Clean up initial file"
# Move the old_a repo files and folders into a subdirectory,
# so they don't collide with the other repo coming later
mkdir CLIOptions
dir -exclude CLIOptions | %{git mv $_.Name CLIOptions}
# Commit the move
git commit -m "Move 'CLIOptions' files into sub-directory"
# Do the same thing for InitFile
git remote add -f InitFile git@bitbucket.org:<username>/InitFile.git
git merge InitFile/master --allow-unrelated-histories
mkdir InitFile
dir -exclude CLIOptions, InitFile | %{git mv $_.Name InitFile} # Attention: Exclude also all previous folders!
git commit -m "Move 'InitFile' files into sub-directory"
Rename a Git repository (on BitBucket.org)
-
Logon to BitBucket; go to the repo’s settings and change the name. Then copy the new URL from the web interface’s ‘Clone’ menu, better logout/login again; else it still showed the old URL for me.
-
Checkout a new clone; or, alternatively: See item 3.
-
Switch into your local project and point the local repo’s Git configuration to the new URL: (You can compare the before/after setting with
git config --list: Look forremote.origin.url=git@bitbucket.org:<username>/<NAME>.git.)git remote set-url origin git@bitbucket.org:<username>/<NAME>.git -
Finally and optionally, rename your local project directory. (Git doesn’t care what name the directory has.)
Migrate a Mercurial project to a Git project (on BitBucket.org)
Bitbucket: Converting Hg repositories to Git
The following expect a Windows system and TortoiseHg to be installed and SSH keys to be configured for BitBucket! And your local Hg repository should be up to date (push/pull/merge before, if needed).
Issues, Wikis and other BitBucket features will not be considered! (Note: You can export issues to a zip file and import that zip file into the new BitBucket repository (overwriting all previous issues there, if any exist already).)
-
Enable the Hg-Git extension in TortoiseHg
TortoiseHg -> Global Settings -> Extensions Tab -> [x] hggit -> OK.
That will also be reflected in the Hg configuration file (C:\Users<username>\mercurial.ini) and look like this:
[extensions] hggit = -
Backup BitBucket project
Backup the soon-to-be-converted Hg repo on BitBucket by example by renaming it in the web interface:
-> Settings: General: Repository details: Update repository details: Name: “ ” rename to “ -hg” -
Create a new Git repo on BitBucket
Create a new repository on BitBucket with the now free original name “
” and select Git as the version control system; don’t create a README file. -
Convert
Go to the local working diretory of your Hg repo and do this (adjust path and URL accordingly):
C:\path\to\hg\proj> hg bookmark -r default master C:\path\to\hg\proj> hg push git+ssh://git@bitbucket.org:<username>/<proj>.gitIf that push command results in an error, you might must update your TortoiseHg/Mercurial installation. In my case, I got fatal error, ending with line:
genpack() got an unexpected keyword argument 'ofs_delta'That was with TortoiseHg 4.5.3 (x64); after updating to TortoiseHg 4.9.1 (x64), all was fine.
-
Modify or clone Git repo
C:\path\to\git\repos> git clone git@bitbucket.org:<username>/<proj>.git
See link above for tips on how to modify an existing working directory instead of downloading a new clone.
Enable Bitbucket Pages
From https://www.w3schools.com/git/git_remote_pages.asp?remote=bitbucket
Bitbucket Cloud lets you publish a website directly from your repository.
Enable
- Create a new repository named
<username>.bitbucket.io. - Add your website files (like index.html) to the repository.
Bitbucket uses the master branch and the root folder by default for Bitbucket Pages.
Make sure your site files are in the root of the repository and pushed to the master branch. - Push your changes to the repo on Bitbucket.
The site will be available at https://<username>.bitbucket.io/.
Disable
- Go to your repository’s Settings -> Pages.
- Click “Disable” or delete the whole repository if you no longer need it.
Push to multiple remote repositories
- https://jigarius.com/blog/multiple-git-remote-repositories
- https://jeffkreeftmeijer.com/git-multiple-remotes/
- https://gist.github.com/rvl/c3f156e117e22a25f242
- https://blog.tinned-software.net/git-and-multiple-remotes/
- https://www.reddit.com/r/git/comments/10orfff/push_code_to_two_repos/
- https://git-scm.com/book/ms/v2/Git-Basics-Working-with-Remotes
TODOs
[TODO] Worktree
Statt “Stash”: Stattdessen mehrere Working Copies (in unterschiedlichen Verzeichnissen) auschecken:
git worktree add ../blah master
+ +- Target Branch
|
+- Target Directory (Outside! Nesting beneath the Git repo is not recommended!)
example-proj <-- The main worktree (with a '.git' directory)
example-proj-hotfix <-- Another worktree (has only a '.git' file(!) that points to the main worktree)
Getting rid of it again (after commit & push):
git worktree remove <DIR> --> "." from within; <PATH> from outside.
List:
git worktree list
[TODO] Checkout
git checkout .
Note: Discards all changes that you haven’t commited yet!
Can’t be undone!
But: Staged files [via git add] remain staged!
Discard all changes, incl. already-staged & unstaged (removes on only the mark)
git reset HEAD | git reset --hard HEAD
git checkout .
HEAD == “Name for the commit one has currently checked-out”
[TODO] ???
> git reset HEAD ................................
: :
:.......o <- staged changes/uncommited changes..:
:
HEAD -> o "Blah"
|
o "Do that"
|
o "Do this"
Local main branch
[TODO] Clean
Remove all untracked files & folders from the repo (can’t be undone):
git clean -df
[TODO] Misc.
-
git rebase --interactive main
https://git-scm.com/docs/git-rebase
I can also usegit rebase --interactive HEAD~5to edit the last 5 commits, but I find rebasing directly on main (or master, or whatever my upstream branch is) kills two birds with one stone. It will show me all commits since I branched off from main, and will simultaneously bring my branch up to date with my latest local copy of main. -
git bisect: Allows you to find when something changed, across all of history, either manually or using automated tests, all in O(log n) time.
[TODO] The main steps/areas of Git
The four main steps(areas?) to submit additions or changes to an existing repo
- Change items in a Working Copy
- Prepare the changes (= add to the staging area/the index)
- Commit changes to the local repo
- Push commited changes from local repo to remote repo
[TODO] Common Git Workflow
- git switch -C new-branch
- (… make changes; time passes…)
- git add . (o.Γ€.)
- git commit -m “Message…”
- git fetch && git rebase Origin/main
- git push
- (make pull request)
Film & Television (58)
How To (73)
Journal (18)
Miscellaneous (4)
News & Announcements (21)
On Software (12)
Powershell (1)
Projects (26)