git notes

Notes about Git, the distributed version control system.

Index

How tos

Delete a tag

Delete it locally then push the change.

git tag -d 1.2.3
git push origin :refs/tags/1.2.3

Reference: How to: Delete a remote Git tag

Remove a file from the last commit

So you have committed some files but you accidentally included a file that you don’t want in the commit.

To remove it, reset the head to the last commit:

git reset --soft HEAD^

Everything will now be the same as before your commit, so you can now commit the correct files.

Remove added file / remove file from index

If you’ve accidentally added a file and you’d like to remove it from the index:

git reset [filename]

Find commit that deleted a line

git log -S<string> path/to/file

Where is the line that was deleted from path/to/file.

Reference: How do I “blame” a deleted line

Overwrite remote branch with local

Delete the remote branch and recreate:

git push origin :branch-name
git push origin branch-name

Reference: How can I choose to overwrite remote repository with local commits?

Delete a remote branch

To delete branch-name from the remote (assuming it’s called origin):

git push origin :branch-name

The colon signals deletion.

Reference: How can I choose to overwrite remote repository with local commits?

Determine whether a file is under version control

whoever@wherever:~/$ git ls-files the/file/to/check --error-unmatch
error: pathspec 'the/file/to/check' did not match any file(s) known to git.
Did you forget to 'git add'?

So the/file/to/check is not under version control. If it was under version control you’d simply see its name echoed.

Reference: git - how to tell if a file is git tracked (by shell exit code)?

Remove a commit

If you have commits A-B-C-D-E and you want to remove C to end up with A-B-D-E:

git rebase -i B

You’ll get an editor which lists the commits from B onwards.

pick C
pick D
pick E

Remove the ‘pick C’ line, save and exit. Commit C will be removed.

IMPORTANT: It can be difficult to push these changes to a remote, so beware! Not sure how to deal with this situation.

List deleted files

git log --diff-filter=D --name-status

Update last commit message

To change the message of the last commit:

git commit --amend -m"The replacement message" (or drop the -m flag to be presented with vim to edit the existing message)

Update last commit

To change the last commit:

Manually undo the last changes and get the index into the state you want instead. Run the following to replace HEAD with the index:

git commit --amend -m"The new message" (or drop the -m flag to be presented with vim to edit the existing message).

See Git Basics - Undoing Things.

Apply a patch

git apply -v --check the_patch.patch

If you don’t get any error messages then it’s safe to apply the patch:

git apply -v the_patch.patch

You can apply to a non default location:

git apply -v --directory=sites/all/modules/foobar patches/foobar.patch

If you don’t get any output, even with the verbose flag -v, then you may be running it from the wrong directory. Make sure you’re at the root of the repository.

Merge and remove branch

See Rails and git - clean branch and merge.

git checkout try_merge
git merge --squash new_featuers
git commit -am"New features"
git branch -D new_features (the -D forces the delete, otherwise git only warns because it doesn't know what the branch is)

Undo last commit

To reset index only, with filesystem unmodified, changes staged:

git reset --soft HEAD^

Reset index, with filesystem modified back to last commit, changes unstaged

git reset --hard HEAD^

There’s also the --soft` flag, to reset index, changes staged.

See Whats the difference between git reset –mixed, –soft, and –hard?.

Revert multiple commits

See Revert a range of commits in git.

You have commits A -> B -> C -> D -> E -> HEAD. You want to revert B to D, to get A -> B -> C -> D -> E -> F -> HEAD, where F contains the reverse of B-D inclusive.

git revert B^..D

Or

git revert HEAD^^^^^..HEAD^^

This creates a new commit that undoes whatever you reverted.

For each commit in the revert you’ll be prompted for a commit message in Vim. Leaving default and closing each is often sufficient.

Use stash

From Git Tools - Stashing

Stash your work for later:

git stash "Work in progress for foo feature"

Make and commit a quick change:

git commit [whatever]

Get your stashed files back:

git stash apply

List stashes:

git stash list

Get particular stash back:

git stash apply [stash name]

Where [stash name] is something like stash@{1}, as given by git stash list.

Create an archive of a repository

From How to do a “git export” (like “svn export”)

WARNING: All of these examples will create archives that extract all files in master without creating a ‘master’ directory, so when you extract the archive be sure to do it in a new directory.

git archive master > /somewhere/master.tar

git archive master | tar -x -C /somewhere/master

git archive --format zip --output /somewhere/master.zip master

git archive master | bzip2 >/somewhere/master.tar.bz2

To get a particular revision of a repository you can add that to the command (using HEAD^^ as the example revision here):

git archive HEAD^^ --format=tar --output=src.tar

Editing commit messages

You can’t. Or at least you shouldn’t:

Instead, you could add a note to the commit by creating a tag (object) for it.

Tree-ish

A “tree-ish” or “treeish” are simply methods of referring to a particular commit without having to use the entire SHA hash.

See Git Tools - Revision Selection.

Compare two revisions of a file

git diff [from revision] [to revision] -- [filename]

Show log of changes for a particular file

git log -- [filename]

Show log on stdout suitable for pipe

This will show log results and drop to the prompt without paging hence without having to explicitly quit:

git --no-pager log

You can disable paging by default by adding the following to ~/.gitconfig, but in this case the -p option doesn’t seem to work (i.e. ‘git -p log’ doesn’t use the less command as default pager like it should).

[core]
  pager = cat

Show N log messages

git log -N

Restore deleted file

Find the last commit that affected the given path. As the file isn’t in the HEAD commit, this commit must have deleted it.

git rev-list -n 1 HEAD -- <file_path>

Then checkout the version at the commit before.

git checkout <deleting_commit>^ -- <file_path>

Or in one command, if $file is the file in question.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Remove remote

git remote rm [name]

Show git config

You can view the config file for a repository manually:

cat .git/config

Or you can use git-config to view your user’s git config (this shows the config in ~/.gitconfig):

git config –global –list

Or your system-wide config (this shows the config in /etc/gitconfig on my Gentoo box):

git config –system –list

Reference: Where is git config coming from?

List all branches

git branch -a

Current branch will be indicated with an asterisk.

List current branch

git branch

List current branch revision

git log

List the remote tracking branches

git branch -r

Search content

From How to grep (search) the git history?:

To search for commit content (i.e., actual lines of source, as opposed to commit messages and the like), what you need to do is:

git grep <regexp> $(git rev-list --all)

This will grep through all your commit text for regexp.

Here are some other useful ways of searching your source…

Search working tree for text matching regular expression regexp:

git grep <regexp>

Search working tree for lines of text matching regular expression regexp1 or regexp2:

git grep -e <regexp1> [--or] -e <regexp2>

Search working tree for lines of text matching regular expression regexp1 and regexp2, reporting file paths only:

git grep -e <regexp1> --and -e <regexp2>

Search working tree for files that have lines of text matching regular expression regexp1 and lines of text matching regular expression regexp2:

git grep -l --all-match -e <regexp1> -e <regexp2>

Search all revisions for text matching regular expression regexp:

git grep <regexp> $(git rev-list --all)

Search all revisions between rev1 and rev2 for text matching regular expression regexp:

git grep <regexp> $(git rev-list <rev1>..<rev2>)

Search log messages

git log --grep=whatever

Note that this only searches the commit messages, not anything else like the filenames.

Search log for commit

git log --pretty=oneline | grep [commit]

Log with filenames

git log --name-status

Show logs that effect particular path

git log <path>

Diff current file with different file at older revision

From GitFaq - Git SCM Wiki.

With command “git diff” you can refer to a commit and file pair:

git diff <commit1>:path/file <commit2>:otherpath/otherfile

As usual, commits can be commit ids, branch names, tags or relative references like HEAD~2. For example:

git diff 06de3718c389fd5038697151c49519f6e9f2dbe0:ChangeLog HEAD~2:ChangeLog.old

Diff with old revisions

To diff whatever with 3 revisions ago:

git diff HEAD^^ whatever

Deploying with capistrano

See this link: Deploying with Capistrano

Discard files in the index

To discard local modifications that are in the index:

git checkout -f

Discard untracked files

To discard local modifications that are not in the index…

Either add the files to the index then discard them.

Or

git clean -d -f

Roll back all to head

git reset --hard HEAD

Restore deleted file

git checkout [file]

Export particular commit

To show contents of a file and pipe to new file (must be run from git repos):

git show <treeish> > /the/file/name

where is e.g. [commit]:[file path from git root]

e.g. git show 8870650408792950c3fce83a11f8614b3378d153:scripts/save_members_list.sh > ~/dev/drupal/scripts/save_members_list.sh

Add submodule

git submodule add [module_path] [install_path]

e.g. git submodule add http://github.com/jfqd/radiant-ssl_requirement-extension.git vendor/extensions/ssl_requirement

Then add files created:

git add .gitmodules
git add [install_path]
git commit -am"Added submodule [module_name]"

To get the submodule’s content you’ll need to initialise it.

git submodule init

A better way is to do this with the update command, as that will work recursively.

Get submodule contents

Note that this does not update the submodule to the lastest commit, but simply checks out the commit stored for the submodule.

git submodule update

git submodule --init --recursive will update and initialise all submodules recursively (i.e. if you have a submodule that itself uses a submodule).

Show submodule status

git submodule status

See available submodule tags

cd [submodule]
git tag

Upgrade submodule

cd [submodule]
git pull
cd ..
git commit -m"Upgraded [submodule]"

Change submodule to different tag/commit

cd [submodule]
git checkout [tag]
git pull
cd ..
git commit -m"Moved [submodule] to [tag]"

Note: git checkout HEAD will not work, becase the submodule is headless. You could use ‘git checkout master’ if master branch is the lastest.

Replace submodule contents

Delete the submodule directory and run:

git submodule update

Note that if you delete only the contents of the submodule directory ‘git submodule whatever’ will do nothing.

Move submodule

You can’t do this. Remove then add.

Remove submodule

From Git Submodule Tutorial

  1. Delete the relevant line from the .gitmodules file.
  2. Delete the relevant section from .git/config.
  3. Run git rm --cached path_to_submodule (no trailing slash).
  4. Commit the superproject.
  5. Delete the now untracked submodule files.

Set up a “bare” repos

A bare repository is a copy of the repository only - i.e. the contents of the .git directory - without the versioned files checked out.

git --bare init

Add remote

  1. Add remote repos as a git remote (to which you’ll push your changes).

    git remote add origin ssh://username@host.com/~/git/app

1a. Can list remotes with git remote show 1b. Can show details of a remote with ‘git remote show origin’

  1. Add the following to .git/config to make the remote default for push/pull.
[branch "master"]
  remote = origin
  merge = refs/heads/master

Show remote URLs

git remote -v

Gotchas

‘Could not read’ and ‘Failed to traverse parents’ errors

If you receive errors like the following, e.g. when cloning a repository or doing a ‘git log’…

error: Could not read 68a3cb35ad4abf437e5d319eb2f3c7387bae9662
fatal: Failed to traverse parents of commit c7ba7750406169816829ee100ac944578b8776fe

…it could be that the repository started life as a shallow clone (i.e. created via git clone –depth 1 [whatever]). In this case, the repository showing the error was a shallow clone of a repository commit c7ba…etc.

You may be able to verify this by finding the object in the cloned repository, by looking in its objects directory for the first two characters of the commit, then looking in that directory for the rest of the commit characters:

> cd /the/location/of/the/cloned/repository/.git/objects/c7
> ls ba7750*
ba77504061...etc.

Git pull after changes pushed from elsewhere

If you have repository A that is being used as a submodule of repository B and you make a change to A in B and push, then you may get the following problem when you attempt to pull from A:

You asked me to pull without telling me which branch you
want to merge with, and ‘branch.master.merge’ in
your configuration file does not tell me, either. Please
specify which branch you want to use on the command line and
try again (e.g. ‘git pull <repository> <refspec>’).
See git-pull(1) for details.

If you often merge with the same branch, you may want to
use something like the following in your configuration file:

[branch “master”]
remote = <nickname>
merge = <remote-ref>

[remote “<nickname>”]
url = <url>
fetch = <refspec>

See git-config(1) for details.

To work around try this…

git pull origin master

Submodule initialisation

If you find that a submodule is not listed in .git/config, which is indicated by a minus sign next to the module commit when running git submodule, then you’ll need to initialise the submodule with git submodule init.

Recursive submodules

If submodule A itself uses submodule B, the updating/initialising the project’s submodules will not filter through to cause submodule B to be updated/initialised.

Be sure to use git submodule update --init --recursive

This will only work on git 1.6 onwards.

For git 1.5 you can use a bash script:

#!/bin/sh

FILES=`find . -type f -name ".gitmodules"`
for f in $FILES
do
  pushd `dirname $f`
  git submodule update --init
  popd
done

Note that if you have nested submodules you will have to run this script once for every nest, because a submodule directory won’t contain the .submodules file until it has been updated.

Submodule ahead of master

If you’re in a submodule and you receive the following message on git checkout (for whatever reason):

Previous HEAD position was 6d347ba... Updated f3-yaml for removal of max-width in handheld css
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.
  (use "git push" to publish your local commits)

…and you want to revert to the latest submodule code and loose your local commits, then use git reset:

git reset –hard

git reset –hard [commit]

Reference: Git submodule pull overwrite/discard any local changes

Last modified: 21/11/2015 Tags:

Related Pages

Other pages possibly of interest:

This website is a personal resource. Nothing here is guaranteed correct or complete, so use at your own risk and try not to delete the Internet. -Stephan

Site Info

Privacy policy

Go to top