My typical git use consists in archiving file modifications for personal projects. Sometimes I share these projects with a few colleagues. We are then 2, 3 or a handful of persons working concurrently on the same project, pushing and pulling changes several times per week or even per day.
We suppose someone has helped you initialise a git repository. Before you modify files, get the latest version of files from the remote repository:
git pull
Work and modify files in the folder. At some point, when your work has reached a certain status, you might want to archive it before you move on to something else. The few commands below tell git to archive the work.
Show which files have been modified in the folder under git control:
git status
Add a file to be committed
git add filename
Or add all files:
git add --all
Commit and describe changes
git commit -m "describe changes made to those files"
Now you can continue working and changing files. Repeat the
git add --all
or git add filename
followed by
git commit -m "describe changes"
each time your reach a
point where you think it’s a good idea to archive your work (when a fix
is implemented, or at the end of the morning). Before you leave your
computer, push the content to the remote repository with:
git push
In case you work with other people on this remote repository, Before you push, you might want to integrate work done by others in your repository. If any new work has been added by others on the remote repository, git will ask you to first do:
git pull
and then:
git push
This simple work flow works well for one user pulling from- and pushing to- a master branch on a remote repository.
Sometimes the vi editor starts. To exit the vi editor:
ESC:q!
Note: you might use a graphical git client with check boxes to add the files to be committed.
Initialise a new repository
git init
Change to the development branch
# If the branch doesn't exist, create it first.
git branch develop
git checkout develop
Work and modify files in the folder. At some point, when your work has reached a certain status, you might want to archive it before you move on to something else. The few commands below tell git to archive the work. All file modifications will be archived with a commit hash which is a unique key describing your changes. The most important part is entering a commit message, it should be sufficiently general to describe your changes with a high level of abstraction and sufficiently specific to be understood amoung all other changes later.
First show which files have been modified in the folder under git control:
git status
Add a file to be committed
git add filename
# Add all files
git add --all
Commit and describe changes
git commit -m "describe changes made to those files"
Now you can continue working and changing files. Repeat the
git add --all
and
git commit -m "describe changes"
each time your reach a
consistant change status.
At some point you will be ready to upload your content to a remote archive. Merge to the master branch
git checkout master
git merge develop
Push contents to the remote repository
git push
See below how to set-up the remote repository with
git remote add origin ssh:repositoryurl
and pushing content
for the first time with git push -u origin master
.
Check status again
git status
Go back to the development branch
git checkout develop
Continue to modify files in the repository.
Add modified markdown files to the next git commit
git add *.md
The star * is a file glob pattern that matches all other path components in between.
Commit messages descripe at a high level what has been changed in the code.
On the linux kernel repository commit messages start with a capital letter and do not have a dot at the end. This style is also what is written in the tidyverse style guide.
Example of a long commit message (like a letter) torvalds/uemacs Stop using ‘short’ for line and allocation sizes.
Extract:
“I really should just learn another editor, rather than continue to polish this turd.”
Add minor changes to the previous commit (git commit –amend):
git commit --amend
git has an auto
complete feature available in a script:
git-completion.bash
.
That script can be loaded in bashrc at the start of the shell. A debian package was made to simply load git-completion.bash for you:
sudo apt install bash-completion
To start work in a new branch:
git branch new_branch_name
git checkout new_branch_name
To compare a file between 2 branches:
git diff branch1 branch2 file_name
To compare the tip of 2 branches
git diff branch1..branch2
To merge changes back to the main branch:
git checkout main
git merge branch1
If there were conflicts, they will be presented in this way:
"The area where a pair of conflicting changes happened is marked with
markers <<<<<<<, =======, and
>>>>>>>. The part before the ======= is typically your
side, and the part afterwards is typically their side."
If I am on a detached head, it is recommended to create a temporary branch (stackoverflow).
git branch temp
git checkout temp
git add -a
git commit -m "description of changes"
git checkout main
git merge temp
Delete uncommitted changes in current working directory:
git checkout branch_name .
See also below git clean.
For solo projects, I use to have this branching strategy:
I never work in the master branch, always in a development branch called
develop
. I mergedevelop
inmaster
, only before pushing modifications back to my remote archive. This simple branching strategy makes it much easier to deal with potential changes in the remote master branch.
But I have now changed to a simpler strategy where I work only on the master branch.
For collaborative projects, we use feature branches or also a dev and a main branch.
Create a branch and start working on it
git branch new-branch-name
git checkout new-branch-name
Push the new branch to the remote repo
git push --set-upstream origin new-branch-name
git push -u origin new-branch-name
Move to a commit in history and create a branch at that commit
git checkout <commit-sha>
git switch -c new-branch-name
I might need to delete a branch at some point:
git branch -d branch_name
Delete a remote branch
git push --delete origin branch_name
git push --d origin branch_name
Check if a branch has been merged before deleting it
git merge-base main compare
Will return the latest common commit between the 2 branches.
To merge branch1
changes to the main
branch:
git checkout main
git merge branch1
--ours
or --theirs
In case of a merge conflict, you can edit the corresponding file(s)
manually in a text editor, or you can decide to keep one of the 2
versions by checking out. For example if you are in the
main
branch
git checkout --ours <filename>
will get the file as it is in the main
branch, while
git checkout --theirs <filename>
will get the file as it is in branch1
. And vice-versa,
if you are currently in a feature branch
git checkout --ours <filename>
will get the file as
it is in the feature branch.
When a file in a status Unmerged paths
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: file_name.ext
Either edit the file, looking for =====
to find the
zones of conflict. Or revert to the latest tracked version of that file
with
git restore --stage file_name.ext
When you fetch a remote repository, you get all its branches. The remote branches can be viewed with:
git branch -r
If there is only one branch with that name, you can simply do (without the remote prefix, only the branch name):
git checkout <branch name>
To create a local branch that tracks the remote branch. You’ll be able to make changes to that local branch and push them to the remote branch later.
https://medium.com/@nitanshu1991/git-branching-conventions-102041e9bb71
“If your branch name is more than one words you should use underscore
_
rather than hyphen-
because-
here separates the two different branch.”
Create and push under a new branch name to the remote repository
git switch -c new-branch-name
git push -u origin new-branch-name
Delete the old branch name locally and in the remote repository
git branch -d old-branch-name
git push --delete origin old-branch-name
Display your user name, email and remote repositories
git config -l
To change username and email globally
git config --global user.name "Your Name"
git config --global user.email you@example.com
Stackoverflow git multiple user names for different projects explains how to change the email for the current repository only
git config user.email personal@example.org
How do I make Git use the editor of my choice for commits?
git config --global core.editor "vim"
Edit the global configuration file
git config --global --edit
How to save user name and password in git
git config credential.helper store
Alternativelly, it’s better to use ssh keys to connect to git repositories.
To see more output when a git command is not working as you would
expect you can prefix it with GIT_TRACE=1
:
GIT_TRACE=1 git commit
To view modified files that have not been committed and to view commit history you can use:
git status
git log
git log --pretty=oneline
Show when the tip of branches have been updated
git reflog
Alternatively, call the repository browser with:
gitk
To view a shorter version of the log file, and get an idea at where I am in the history:
git log --graph --decorate --all --pretty=oneline
You can define an alias for git log as explained be Fred here:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%C(bold blue)<%an>%Creset' --abbrev-commit"
The new alias can then be used with
git lg
Use tags to specify important points in history, such as software versions.
Shows the changes between the working directory and the index.
git diff
Shows the changes between the index and the HEAD
git diff --cached
Shows all the changes between the working directory and HEAD
git diff HEAD
Compare between 2 commits
git diff <commit hash 1> <commit hash 2>
List all revision of a given line number in the git history
FILE=filename.csv
LINE=1
git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE
Useful to track different versions of CSV files headers.
To consider commas a separator when using word diff in csv file, you can use
git diff --word-diff-regex="[^[:space:],]+"
# Or
git diff --color-words="[^[:space:],]+" x.csv y.csv
Show which change happened in a particular commit
git show <commit-hash>
Show only word changes
git show --word-diff <commit-hash>
Show all commits by a person
git log --author="Author Name"
With a regular expression
git log --author="^John"
To see the commit number and author of each line in a file use
git blame filename
To ignore all files in a folder but not the folder itself. Put this .gitignore into the folder, then git add .gitignore
*
!.gitignore
To exclude everything except a specific directory foo/bar (note the /* - without the slash, the wildcard would also exclude everything within foo/bar):
/*
!/foo
/foo/*
!/foo/bar
So question how can I add a blank directory to a git repository
some answers suggest using .gitkeep
or simply
.keep
because files starting with “.git” should be reserved
for git usage.
Git run enables to pull from many repositories with a single command
configuration was a bit complicated on debian
Install nodejs and npm from the backports
sudo apt -t stretch-backports install nodejs
sudo apt -t stretch-backports install npm
sudo apt install build-essential
Configure nmp to run only for the local user configure npm to use a different directory citing docs.npmjs.com Manually change npm’s default directory
in your home directory, create a directory for global installations:
mkdir ~/.npm-global
Configure npm to use the new directory path:
npm config set prefix '~/.npm-global'
Install Git run:
npm install -g git-run
Edit your bash profile:
vim ~/.bash_aliases
and add this line:
export PATH=~/.npm-global/bin:$PATH
Then the configuration file is a .json file on the home folder. Edit it:
vim ~/.grconfig.json
For example:
{
"tags": {
"all": [
"/home/paul/repos/bioeconomy_notes",
"/home/paul/repos/bioeconomy_papers",
"/home/paul/repos/cbm3_python",
"/home/paul/repos/cbmcfs3_data",
"/home/paul/repos/cbmcfs3_pub",
"/home/paul/repos/cbmcfs3_runner",
]
}
}
Show the status and pull from many repos:
gr git status
gr git pull
https://git-scm.com/docs/git-bisect
“This command uses a binary search algorithm to find which commit in your project’s history introduced a bug. You use it by first telling it a”bad” commit that is known to contain the bug, and a “good” commit that is known to be before the bug was introduced. Then git bisect picks a commit between those two endpoints and asks you whether the selected commit is “good” or “bad”. It continues narrowing down the range until it finds the exact commit that introduced the change. In fact, git bisect can be used to find the commit that changed any property of your project; e.g., the commit that fixed a bug, or the commit that caused a benchmark’s performance to improve. To support this more general usage, the terms “old” and “new” can be used in place of “good” and “bad”, or you can choose your own terms. See section “Alternate terms” below for more information.”
Display the modification log
git log
In the log, you can copy the beginning of a commit hash for use as
commit_sha
in the reset commands below.
Display the log of a particular branch (after a fetch for example)
git log origin/master
Display the log of a particular file
git log path/filename
Display a compact log for one file or one directory only
git log --abbrev-commit --pretty=oneline path_to_file
Edit ~/.gitconfig
to define an alias that shows the last
10 log entries in a compact way:
[alias]
lkj = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(cyan)<%an>%Creset' --abbrev-commit -10
This alias also works with the log of one file only
git lkj path/filename
Show the number of lines modified in each files for each commit:
git log --numstat
A one liner version showing the number of files changes, number of lines inserted and deleted how to get log with short stat in one line:
git log --pretty="@%h" --shortstat | tr "\n" " " | tr "@" "\n"
git log --pretty=format:'%h,%an,%ad,"%s"' --date=iso -10
Edit ~/.gitconfig
to define it as an alias:
logcsv = log --pretty=format:'%h,%an,%ad,\"%s\"' --date=iso
Another version adding stats on the number of files changes, number of lines inserted and deleted based on how to get log with short stat in one line:
git log --pretty=format:'linebegin%h,%an,%ad,"%s"' --shortstat --date=iso | tr "\n" "," | sed -E 's/linebegin|,*$/\n/g'
Simpler solution using paste to glue lines together (there is an issue with extra spaces at the beginning and in the middle of some lines):
git log --pretty=format:'%h,%an,%ad,"%s",' --shortstat --date=iso | paste - - - #> /tmp/gitlog.csv
Find the last commit where a file was still present in the repository.
Show commits where a particular file was modified, it continues history even if the file was renamed.
git log --follow -- notebooks/wood/belarus_ukraine_russia/wood_bur_comtrade_monthly.Rmd
Show all commits where a file was modified
git log --full-history -- biomass_mandate_s2p/biomass_mandate_s2p_report.Rmd
The tig utility is a repository browser for git log and git diff.
In case you entered a wrong commit message, you can edit the last commit message with:
git commit --amend
In case you forgot a file, you can add a file to the last commit with:
git add filename
git commit --amend
A comment in How
to change past commit to include a missed file? specifies that
commits before and after --amend
have different hashes,
even if only the commit message is changed. The use of
--amend
is only for private commits, which have not yet
been shared with others.
Rewriting commits older than the previous one is much harder. It requires the use of git rebase. I regularly want to fix typo in the git log, but it is not possible it was made unflexible on purpose. Explained in this Stackoverflow Answer
“The real reason git doesn’t allow you to change the commit message ends up being very simple: that way, you can trust the messages. If you allowed people to change them afterwards, the messages are inherently not very trustworthy.”
“If you haven’t yet pushed your changes, you can also do a soft reset:”
git reset --soft HEAD^
“This will revert the commit, but put the committed changes back into your index. Assuming the branches are relatively up-to-date with regard to each other, git will let you do a checkout into the other branch, whereupon you can simply commit:”
git checkout branch
git commit -c ORIG_HEAD
“The -c ORIG_HEAD part is useful to not type commit message again.”
It is safe to use rebase as long as the commits have not been pushed to another repository. To rename older commits, simply run:
git rebase -i
git rebase -i @~9 # Show the last 9 commits in a text editor
Rebase will show the last 3 commits by default in the vim editor. Each line starts with “pick” followed by the commit hash and commit message. You can then replace the “pick” word in the vim editor by the command you want to achieve, press “escape”, “:wq” and peform the git command on the selected commit.
See also :
Answers to a StackOverflow question How to modify a specified commit?.
10 things I hate about git Translation of the man page which he considers hard to understand: “git-rebase – Sequentially regenerate a series of commits so they can be applied directly to the head node”
You can either go through with the rebase and resolve the conflict. In case you just want to get to the status of the remote branch
Abort the Rebase:
git rebase --abort
Reset the local branch
git fetch origin
git reset --hard origin/main
See also the section on checkout --ours
or
--theirs
.
To keep only the version of their changes
git checkout --theirs .
SO question in a case where the project was not made available publicly yet.
rebase -i
git filter-branch
Remove all files also those not tracked by git because they are in .gitignore. For example output pdf files and auxiliary files generated from latex or from pandoc.
git clean -xf
Remove all files including directories
git clean -f -d
Remove local (untracked) files from my current Git branch
Show what will be deleted with the -n option:
git clean -f -n
Then - beware: this will delete files - run:
git clean -f
Alternatively clean in interactive mode:
git clean -i
Identify the commit identity in the log and copy its sha number. Then to go back to this state for the whole folder:
git reset --hard commit_sha
Do this before pushing only!
Once you have pushed the changes, you need to revert the commit and commit those changes as well:
git revert -m 1 HEAD~
git revert commit_sha
See https://stackoverflow.com/questions/9804211/can-not-push-changes-after-using-git-reset-hard
Use the begining of a commit_sha
copied from the
log.
To remove a commit where I accidentaly commited a very large file. I used how to remove a too large file in a commit:
git reset HEAD^
Then added the large file to .gitignore and committed again.
Git restore
can be used to “restore working tree files”.
The git checkout
command can also be used for this and many
other things. Git restore was created to simplify and have a dedicated
command that only focuses on restoring files.
To go back to this state for only one file, see git checkout
git checkout commit_hash path_to_file/file_name
No need to enter the commit hash to get to get the file from the latest commit
git checkout path_to_file/file_name
Checkout the older revision of a file under a new name
git show commit_sha:filename > new_file_name
See also alias and git grep below.
Revert an unwanted commit with a new commit doing exactly the reverse operation
git revert <commit hash>
Linus Torvald’s advice on reverting a merge
“When you have a problem you are chasing down, and you hit a”revert this merge”, what you’re hitting is essentially a single commit that contains all the changes (but obviously in reverse) of all the commits that got merged. So it’s debugging hell, because now you don’t have lots of small changes that you can try to pinpoint which part of it changes.
But does it all work? Sure it does. You can revert a merge, and from a purely technical angle, Git did it very naturally and had no real troubles. It just considered it a change from “state before merge” to “state after merge”, and that was it. Nothing complicated, nothing odd, nothing really dangerous. Git will do it without even thinking about it.
So from a technical angle, there’s nothing wrong with reverting a merge, but from a workflow angle it’s something that you generally should try to avoid.
If at all possible, for example, if you find a problem that got merged into the main tree, rather than revert the merge, try really hard to bisect the problem down into the branch you merged, and just fix it, or try to revert the individual commit that caused it.
Yes, it’s more complex, and no, it’s not always going to work (sometimes the answer is: “oops, I really shouldn’t have merged it, because it wasn’t ready yet, and I really need to undo all of the merge”). So then you really should revert the merge, but when you want to re-do the merge, you now need to do it by reverting the revert.”
Show dangling blobs and trees with the git file system check command:
git fsck
Stackoverflow What is a dangling blob?
“Dangling blob = A change that made it to the staging area/index, but never got committed. One thing that is amazing with Git is that once it gets added to the staging area, you can always get it back because these blobs behave like commits in that they have a hash too!!”
git fsck
shows dangling blobs and dangling trees.
Running git cat-file -p blob_sha > /path/to/the/file
followed by git diff
shows me a lot of line deletions. I
have to explore around to find which blob is adding content back.
To show the content of a blob
git show blob_sha
To retrieve a single file from a dangling blob
git cat-file -p blob_sha > /path/to/the/file
To retrieve many files from a dangling tree SO recover dangling blobs in git
git checkout commit_sha -- .
I was on a dev branch and committed a change to the README file. But in fact I wanted this change - related to installations instructions - to be visible by all users immediately. So that commit should have been on the main branch. The problem is that I had other commit in the dev branch that were not ready yet to be shared on the main branch. In order to pick just the commit that changed the README file and put it in the main branch I did:
git cherry-pick <commit-hash>
For colleagues who need a GUI:
A section of the git book on Graphical User Interfaces describes the default git-gui and gitk graphical user interfaces to prepare commits and view the git log history. It also describes the github desktop client and in particular it’s “sync” feature:
“The main way you interact with other repositories over the network is through the “Sync” feature. Git internally has separate operations for pushing, fetching, merging, and rebasing, but the GitHub clients collapse all of these into one multi-step feature. Here’s what happens when you click the Sync button:
git pull --rebase. If this fails because of a merge conflict, fall back to git pull --no-rebase. git push.
This is the most common sequence of network commands when working in this style, so squashing them into one command saves a lot of time. ”
Get help on a command (will start a web browser):
git init --help
Press y
to get a permalink to the current file on
Gitlab. The URL will include the hash number of the latest commit. https://docs.github.com/en/repositories/working-with-files/using-files/getting-permanent-links-to-files
https://docs.gitlab.com/ee/user/project/issues/crosslinking_issues.html
To link between issues in different repositories in the same project,
prefix the #issue number
with the project name:
project_name#1
If they are not in the same group, you can add the full URL to the issue (https://gitlab.com/
/ /-/issues/ ).
To mark an issue as duplicate:
/duplicate #issue_number
On the Gitlab labels page:
“Labels can be applied to issues and merge requests. Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.”
Priority | Importance | Intention |
---|---|---|
~priority::1 |
Urgent | We will address this as soon as possible regardless of the limit on our team capacity. |
~priority::2 |
High | We will address this soon and will provide capacity from our team for it in the next few releases. |
~priority::3 |
Medium | We want to address this but may have other higher priority items. |
~priority::4 |
Low | We don’t have visibility when this will be addressed. |
By default, job artifacts are not kept on failure. To enable this add
a when
clause to .gitlab-ci.yaml
artifacts:
when: always
paths:
- notebooks
View the usage quota through time and by repository at the top project level under settings / usage quotas.
Site URL available in the project repository under Settings/Pages
The app’s built output files are in a folder named “public”
The public folder also needs to be published as an artifact. See the
.gitlab-ci.yml
file in this repository.
Create a deploy token on the repository page. It also works at the project level for several repos.
A deploy token makes it possible to clone in an unauthenticated way.
git clone https://username:token@gitlab.com/user/repo.git
Check usage quotas for a group at (replace group_name by the actual group name):
https://gitlab.com/groups/group_name/-/usage_quotas
For a user at (link works as is):
https://gitlab.com/-/profile/usage_quotas#pipelines-quota-tab
How to renormalize line endings in all files in all revisions?
git add --renormalize .
This is usually taken care of at the system level. But sometimes when you share files with windows machines (accessing them on a shared folder for example) you end up with commits that show a lot of modifications because the windows line ending LRLF appears in the linux machine. Configuring git to handle line endings To force the line ending to be LF only, create a .gitattributes file which contains:
text eol=lf
Older content related to pages built from branches.
SO answer to the question “How to add a git repo as a submodule of itself? (Or: How to generate GitHub Pages programmatically?)”: An alternative to using Git Submodules to generate GitHub Pages is to use Git Subtree Merge Strategy.
In fact I didn’t use quite that strategy and I instead cloned a temporary copy of my repository. Created the gh-page branch. Pushed it to github. Then I went back to the original repository (where I have a few large untracked data files I find handy to keep for analyses purposes).
Then within the inst folder, I cloned only the gh-branch. To clone only one branch:
git clone -b mybranch --single-branch git://sub.domain.com/repo.git
Then I renamed the folder to “web”, so that I had a inst/web folder, tracking the gh-branch. inst/web is ignored in the main repository.
Gitlab has an integrated CI mechanism, * Create
a pages website by using a CI / CD template * Rendering
an R markdown presentation to gitlab pages uses the
rocker/verse:4.0.0
docker image. Posted on September 16,
2020. * GitLab
CI for your bookdown project Uses the
rocker/verse:4.0.2
docker image. Posted on 2020-09-08. A
setup generating pages for the master branch and also for merge
requests.
To generate html pages from markdown and publish them, I added a
.gitlab-ci.yml
to the repository. The CI deployment is
visible on the paulrougieux.jobs
page. Clicking on “running” displays the latest activity of an ongoing
build. It starts with “Pulling docker image rocker/verse:4.0.0 …”. Once
the build is finished, the completed page is visible at https://paulrougieux.gitlab.io/paulrougieux/
Add a remote repository with:
git remote add git@github.com:paulrougieux/paulrougieux.github.io.git
# or
git remote add reponame https://repositoryurl
Change the url of a remote repository
git remote set-url origin git@github.com:paulrougieux/paulrougieux.github.io.git
When a repository is connected to several remote repositories, you can push content to repositories by specifying their names
git push -u origin master
git push -u anotherrepository master
To change the default git remote, push with :
git push -u origin master
Then later push of that branch to that remote can be made simply with:
git push
Another command without specifying the remote and the branch
$ git push -u
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin master
After I run this set upstream flag, I can push to the remote server. Then I get this message
[...]
* [new branch] master -> masterBranch master set up to track remote branch master from origin.
I’ll have to figure out what this does.
Based on this blog post I added the push remote twice to the origin repo as such :
git remote set-url --add --push origin git@gitlab.com:paulrougieux/paulrougieux.git
git remote set-url --add --push origin git@github.com:paulrougieux/paulrougieux.github.io.git
The output of git push -v shows that it is now pushing to both repositories
git push -v
Pushing to git@gitlab.com:paulrougieux/paulrougieux.git
To gitlab.com:paulrougieux/paulrougieux.git
= [up to date] master -> master
updating local tracking ref 'refs/remotes/origin/master'
Everything up-to-date
Pushing to git@github.com:paulrougieux/paulrougieux.github.io.git
To github.com:paulrougieux/paulrougieux.github.io.git
= [up to date] master -> master
updating local tracking ref 'refs/remotes/origin/master'
Everything up-to-date
Explanation on rebase versus merge
“If you pull remote changes with the flag –rebase, then your local changes are reapplied on top of the remote changes.”
git pull --rebase
“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.”
git pull --merge
“It is best practice to always rebase your local commits when you pull before pushing them.”
This can be set as a global configuration with
git config --global pull.rebase true
Pull a newly created branch from the remote repository
git fetch
Rename a file
git mv file_name file_name_new
Change the case of a file on a windows FAT 32 system:
git mv load.r load2.R
git mv load2.R load.R
If a file or folder has been renamed outside of git, I get this warning:
$ git add .
warning: You ran 'git add' with neither '-A (--all)' or '--ignore-remo
whose behaviour will change in Git 2.0 with respect to paths you removed
Paths like 'docs/efi/efi_logo_rgb_small_siw.jpg' that are
removed from your working tree are ignored with this version of Git.
* 'git add --ignore-removal ', which is the current default,
ignores paths you removed from your working tree.
* 'git add --all ' will let you also record the removals.
Therefore I think I should always run “git add –all” after I have removed or renamed files.
Example from the git grep help page. Looks for time_t in all tracked .c and .h files in the working directory and its subdirectories.
git grep 'time_t' -- '*.[ch]'
Search all files in the subdirectory “subdir” for lines containing the words “factor” and “item”. Show 2 lines of context (2 leading and 2 trailing lines).
git grep -e item --and -e factor -C 2 -- subdir/
Search all R markdown files containing the word lyx ignore the case:
git grep -i lyx -- *.Rmd
Stackoverflow: How to search committed code in the git history?
Search in all possible locations in all commits
git grep <regexp> $(git rev-list --all)
Search for a particular location in the git repo
git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util
The above grep commands will give you a list of commit sha where the grep pattern was present in the repo. You can then checkout the older revision of a file under a new name
git show commit_sha:filename > new_file_name
Get unique list of import statements in python files
git grep -h import -- "*.py" | sort --unique
For example:
git grep -e module_dir --and -e "import"
For example (SO):
git grep -e "index=True" --and --not -e "ignore_index"
Use git grep to replace strings in many files in the directory :
git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'
See also the refactor function in the bash page.
Count the number of lines of code for each language in a remote git repository according to this stackoverflow answer
#!/usr/bin/env bash
git clone --depth 1 "$1" temp-linecount-repo &&
printf "('temp-linecount-repo' will be deleted automatically)\n\n\n" &&
cloc temp-linecount-repo &&
rm -rf temp-linecount-repo
“This script requires CLOC (“Count Lines of Code”) to be installed. cloc can probably be installed with your package manager”
sudo apt install cloc
“You can install the script by saving its code to a file
cloc-git
, runningchmod +x cloc-git
, and then moving the file to a folder in your$PATH
such as/usr/local/bin
.”
Usage
cloc-git https://github.com/evalEmpire/perl5i.git
Creating an annotated tag
git tag -a v1.4 -m 'my version 1.4'
git tag v0.0.2 -m "Version 0.0.2"
A regular push command won’t push a tag (bitbucket), to push all your tags :
git push origin --tags
List tags
git tag -l
You can add a tag after the fact. To tag an earlier commit, specify the commit checksum or part of it:
git log --pretty=oneline
git tag -a v1.2 -m 'version 1.2' 9fceb02
Delete a tag
git tag -d tag_name
To delete a tag on the remote server as well
git push --delete origin tagname
Return all files in the repository to a particular tag:
git checkout tags/v0.1
Optionally you can checkout and create a new branch to commit your changes with:
git checkout tags/o.1 -b newbranchname
In one repo:
git grep TODO
In multiple repos (using git run):
gr git grep "^TODO "
Git is useful as a version management on its own. But it’s even more usefull when code can be back-up online. * Free public git storage is availble on Github. * Free public and private git storage are available on Bitbucket, with up to 5 collaborators per project. * Free public and private git storage are available on Gitlab.
Commands I’ve used to upload content to an existing repository github.com/paul4forest/forestproductsdemand are:
git remote add origin https://github.com/paul4forest/forestproductsdemand
git pull origin master
git add
git commit -m "Explanatory message"
git push origin master
Commands to upload content to a fresh repository from bitbucket :
mkdir /path/to/your/project
cd /path/to/your/project
git init
git remote add origin ssh://git@bitbucket.org/username/bbreponame.git
# Upload and set the local changes as upstream
git push -u origin master
See also this discussion on why do I need to set upstream?
Commands to copy an existing repository from bitbucket :
git clone git@bitbucket.org/username/bbreponame.git
See Generating a new SSH key and adding it to the ssh-agent and Adding a new SSH key to your GitHub account
To test if my new ssh key worked with github, I created a branch and pushed it to github. Then I deleted the branch locally and remotely:
git branch "key"
git checkout key
git push --set-upstream origin key
# Checked that the "key" branch became visible on github
git checkout master
git branch -d key
git push origin --delete key
For example you edit a file in branch develop
git checkout develop
echo "blabla" > newfile.txt
Imagine you are in the middle of your work and need to do an urgent modification in another branch. To move to another branch, you would normaly need to commit this change. If you don’t want to commit the change yet. You can store temporary changes with the command:
git stash
Move to the master branch
git checkout master
# perform important operation in the master branch.
Get back to the develop branch and reload uncommited changes
git checkout develop
git stash pop
Subversion is another version control system. It is different than git and should be on another page, but since I don’t expect to use it very much, it probably makes sense to keep a Subversion section under the git page here. See also wiki.debian.org small SVN tutorial.
Install subversion from the Debian repository
sudo apt install subversion
Load the latest version of some repository
svn checkout --username yourusername http://repositoryurl
Get help on a command
svn help log
See the last 4 log entries
svn log -l 4
Bring changes from the repository HEAD into the working copy
svn up
synchronize working copy to revision given by -r.
svn up -r10860
show the status
svn status
show differences
svn diff
This git page is the continuation of my blog post on git commands.
Presentations:
Power Your Workflow With Git (towards 43 minutes, an animation of branches and merging) A recommendation if you work in a team, don't use pull, but use fetch + merge.
Getting Started with GitHub + Git
Workflow:
Mixing private and public repository in Git workflow
Book:
Tutorial:
Blogs: