Skip to content

Instantly share code, notes, and snippets.

@baopham
Created February 23, 2012 19:32
Show Gist options
  • Save baopham/1894530 to your computer and use it in GitHub Desktop.
Save baopham/1894530 to your computer and use it in GitHub Desktop.
git commands notes

To delete a commit

Assuming you are sitting on that commit

git reset --hard HEAD~1

Or

git reset --hard <sha1-commit-id>

If the repo has already been pushed, need to do a force push to get rid of it

git push origin HEAD --force

To delete a submodule

  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 and delete the now untracked submodule files.

To change first commit's message

# checkout the root commit
git checkout <sha1-of-root>

# amend the commit
git commit --amend

# rebase all the other commits in master onto the amended root
git rebase --onto HEAD HEAD master

To fix "Git submodule head 'reference is not a tree' error"

Assuming the submodule's repository does contain a commit you want to use (unlike the commit that is referenced from current state of the super-project), there are two ways to do it.

The first requires you to already know the commit from the submodule that you want to use. It works from the “inside, out” by directly adjusting the submodule then updating the super-project. The second works from the “outside, in” by finding the super-project's commit that modified the submodule and then reseting the super-project's index to refer to a different submodule commit.

Inside, Out

If you already know which commit you want the submodule to use, cd to the submodule, check out the commit you want, then git add and git commit it back in the super-project.

Example:

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

Oops, someone made a super-project commit that refers to an unpublished commit in the submodule sub. Somehow, we already know that we want the submodule to be at commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Go there and check it out directly.

Checkout in the Submodule

$ cd sub
$ git checkout 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

Note: moving to 5d5a3ee314476701a20f2c6ec4a53f88d651df6c which isn't a local branch If you want to create a new branch from this checkout, you may do so (now or later) by using -b with the checkout command again. Example:

$ git checkout -b <new_branch_name>
HEAD is now at 5d5a3ee... quux
$ cd ..

Since we are checking out a commit, this produces a detached HEAD in the submodule. If you want to make sure that the submodule is using a branch, then use git checkout -b newbranch <commit> to create and checkout a branch at the commit or checkout the branch that you want (e.g. one with the desired commit at the tip).

Update the Super-project

A checkout in the submodule is reflected in the super-project as a change to the working tree. So we need to stage the change in the super-project's index and verify the results.

$ git add sub

Check the Results

$ git submodule update
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

The submodule update was silent because the submodule is already at the specified commit. The first diff shows that the index and worktree are the same. The third diff shows that the only staged change is moving the sub submodule to a different commit.

Commit

git commit

This commits the fixed-up submodule entry.

Outside, In

If you are not sure which commit you should use from the submodule, you can look at the history in the superproject to guide you. You can also manage the reset directly from the super-project.

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

This is the same situation as above. But this time we will focus on fixing it from the super-project instead of dipping into the submodule.

Find the Super-project's Errant Commit

$ git log --oneline -p -- sub
ce5d37c local change in sub
diff --git a/sub b/sub
index 5d5a3ee..e47c0a1 160000
--- a/sub
+++ b/sub
@@ -1 +1 @@
-Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
+Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
bca4663 added sub
diff --git a/sub b/sub
new file mode 160000
index 0000000..5d5a3ee
--- /dev/null
+++ b/sub
@@ -0,0 +1 @@
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

OK, it looks like it went bad in ce5d37c, so we will restore the submodule from its parent ce5d37c~.

Alternatively, you can take the submodule's commit from the patch text 5d5a3ee314476701a20f2c6ec4a53f88d651df6c and use the above “inside, out” process instead.

Checkout in the Super-project

$ git checkout ce5d37c~ -- sub

This reset the submodule entry for sub to what it was at commit ce5d37c~ in the super-project.

Update the Submodule

$ git submodule update
Submodule path 'sub': checked out '5d5a3ee314476701a20f2c6ec4a53f88d651df6c'

The submodule update went OK (it indicates a detached HEAD).

Check the Results

$ git diff ce5d37c~ -- sub
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

The first diff shows that sub is now the same in ce5d37c~. The second diff shows that the index and worktree are the same. The third diff shows the only staged change is moving the sub submodule to a different commit.

Commit

git commit

This commits the fixed-up submodule entry.

Ignore local changes to one file

e.g: .rvmrc

Add .rvmrc to the local git exclude file

$ echo ".rvmrc" >> .git/info/exclude

Remove .rvmrc from files being tracked for changes

$ git update-index --assume-unchanged .rvmrc

Merge specific file from different branch

$ git checkout other-branch <path>

Delete a remote branch

$ git branch -D <branch>
$ git push origin :<branch>

###To see if any of the remote-tracking branches already contain the currently checked out commit

$ git branch -r --contains HEAD

Split a subpath into a new repo

Suppose we have a repo with this layout

bin/
lib/
spec/
README.md

And we want to split lib/ into a new separate repo:

$ git filter-branch --prune-empty --subdirectory-filter lib master

Now we have a re-written master branch that contains the files that were in lib/

Check for commits that are not yet pushed to remote repo

$ git log origin/master..master

Or more generally,

$ git log <since>..<until>

Use with grep:

$ git log <since>..<until> | grep <commit-hash>

Use git-rev-list to search for a specific commit:

$ git rev-list origin/master | grep <commit-hash>
@baopham
Copy link
Author

baopham commented Feb 23, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment