Differences between revisions 1 and 36 (spanning 35 versions)
Revision 1 as of 2010-08-11 22:48:22
Size: 290
Editor: SamatJain
Comment:
Revision 36 as of 2021-05-01 00:51:22
Size: 7641
Editor: SamatJain
Comment: git remote prune origin
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
<<TableOfContents>>

See also: [[CodingStyle/Git]]

== Workflow for gitorious and github ==

Initial checkout:

{{{#!highlight sh
# Fork repo on gitorious/github
# Pull repo from gitorious/github
# Add remote for upstream, e.g.
cd Spoon-Knife
git remote add upstream git://github.com/octocat/Spoon-Knife.git
git fetch upstream
}}}

See [[https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork|Configuring a remote for a fork]]

When needing to merge upstream changes back into master:

{{{#!highlight sh
# Make sure we're in the branch we want to be in (i.e. master)
git checkout master
git fetch upstream
# Merge from master branch of upstream into current branch
git merge upstream/master
}}}

== Cookbook ==

=== Delete remote branch ===

{{{#!highlight sh numbers=off
git push origin :name-of-remote-branch
# OR
git push origin --delete name-of-remote-branch
}}}

=== Reverting changes ===

Amend the previous commit that has not been propogated (i.e. undo it, then start a new one with the pending changes in the index):

{{{
git commit --amend -a -m "New commit message"
}}}
Line 4: Line 51:
git reset --soft HEAD^
}}}

just changes the repository without changing the files you've edited on disk. However:

{{{
Line 7: Line 60:
For a commit that has been propagated, there is no way to undo. However, the following will create a new commit undoing the previous commit's changes: will reset both repository and revert files.

Once
a commit that has been propagated, there is no way to undo. However, the following will create a new commit undoing the previous commit's changes:
Line 12: Line 67:

To only change a commit message for a commit that has not been propogated:

{{{
git commit --amend
}}}

=== Pull with rebase instead of merge ===

{{{
git pull --rebase
}}}

Configure a branch to always do a rebase instead of a merge:

{{{
git config branch.$BRANCH_NAME.rebase true
}}}

=== Enforce .gitignore ===

Remove files from the repository that should have been ignored by .gitignore:

{{{
git rm -r --cached .
git add .
git status
git commit -m ".gitignore is now working"
}}}

=== Search ===

{{{#!highlight sh numbers=off
# Search commit log (i.e. messages) for given needle in all branches
git log --all --grep='needle'
# As above, but search reflog (much slower)
git log -g --grep='needle'
# Search contents of commits
git grep -F 'needle' $(git rev-list --all)
# Search contents of commit in a large repository
git rev-list --all | parallel -j4 -k -X git grep --color=always -F 'needle'
# Search branches (has problems)
git branch -a | tr -d \* | parallel -k git grep --color=always -iF 'needle'
}}}

=== Ignore whitespace bullshit ===

{{{
# Ignore white space when pulling or merging
git pull -Xignore-space-change
git merge -Xignore-space-change
git merge -Xignore-all-space

# Ignore white space changes when diff'ing
git diff --ignore-space-change
}}}

=== Rebase a branch ===

{{{#!highlight sh numbers=off
# Without having branch-you-want-to-rebase checked out
git rebase branch-you-want-to-rebase branch-to-rebase-from
# With having branch-you-want-to-rebase checked out
git checkout branch-you-want-to-rebase
git rebase branch-to-rebase-from
}}}

Rebase off a branch that itself had been rebased (keep the un-rebased branch around as old-branch-to-rebase-from):

{{{#!highlight sh numbers=off
git rebase --onto branch-to-rebase-from old-branch-to-rebase-from branch-you-want-to-rebase
}}}

If you want to rebase but get updated stamps (do this independently of reordering/merging commits with `git rebase -i`:

{{{#!highlight sh numbers=off
git rebase --ignore-date
}}}

=== Interactive rebase ===

Interactive rebase for only certain commits:
{{{#!highlight sh numbers=off
# Rebase only the last 2 commits
git rebase -i HEAD~2
# All commits that are on feature branch, but not on trunk branch
git rebase -i trunk
}}}

== Problems ==

=== Cannot lock ref error ===

{{{
error: cannot lock ref 'refs/remotes/origin/bugfix/SPL-178301-lookups-cache-results-incorrectly':
}}}

is caused by your local repository's copy of the origin repository's branches getting corrupted. To fix:

{{{#!highlight sh numbers=off
git remote prune origin
}}}

It will not touch any of your local branches with your edits, or anything remote, just your local repo's knowledge of remote branches.

== Per-repository user settings ==

{{{#!highlight sh numbers=off
git config user.name 'Samat K Jain'
git config user.email 'nobody@example.com'
}}}

== Cleaning ==

{{{#!highlight sh numbers=off
# Discard all unstaged changes in CWD
git checkout -- .
# Remove untracked files and directories, dry run. `-n` for dry run.
git clean -df -n
}}}

== GPG Signing ==

{{{#!highlight sh
# GPG sign all previous commits. Careful!
git filter-branch -f --commit-filter 'git commit-tree -S "$KEY_ID"' HEAD
}}}

== Submodules ==

In the below, TARGET_DIR is something like `vendor/some-package`.

=== Cloning a project w/ submodules ===

First clone:

{{{#!highlight sh numbers=off
git clone --recurse-submodules …
}}}

If you forgot `--recurse-submodules`, can run:

{{{#!highlight sh numbers=off
git submodule update --init --recursive
}}}

=== Adding submodules to a project ===

{{{#!highlight sh numbers=off
git submodule add $REPOSITORY_URL $TARGET_DIRECTORY
}}}

You need to start tracking the new `.gitmodules` file (just like `.gitignore`), as well as a "file" representing the submodule. `git status` will show it as $TARGET_DIRECTORY.

{{{#!highlight sh numbers=off
git add .gitmodules $TARGET_DIRECTORY
git commit -m 'Started tracking $REPOSITORY_URL as submodule'
}}}

=== Update submodules ===

Go to each submodule, fetch, and update:

{{{#!highlight sh numbers=off
git submodule update --remote --recursive
# git commit
}}}

=== Remove submodules ===

Go to each submodule, fetch, and update:

{{{#!highlight sh numbers=off
git submodule rm $TARGET_DIR
# git commit
# Completely remove submodule (will need to be init again if you go backwards in history) to save disk space
rm -Rf .git/modules/$TARGET_DIR
}}}

Will be done with a `git pull` automatically if `submodule.recurse` option is True.

=== Misc ===

Tell git to track a specific branch of a submodule, e.g. "master":

{{{#!highlight sh numbers=off
git config -f .gitmodules submodule.${TARGET_DIR}.branch master
# commit .gitmodules
}}}

`-f` is specified so that `.gitmodule` can be updated and other people using the repository can track the same branch. Omit this if you don't care.

=== Settings ===

{{{#!highlight sh numbers=off
# `--recursive` for everything but `git clone`
git config --global submodule.recurse true
# Show summary of submodule changes in `git status`
git config --global status.submodulesummary true
# Prettier diff for submodules
git config --global diff.submodule log
}}}

== Interesting reading ==

[[http://tom.preston-werner.com/2009/05/19/the-git-parable.html|The Git Parable]]: Describes building a system like git, from the ground-up

[[https://wikileaks.org/ciav7p1/cms/page_1179773.html|CIA's git tips & tricks]] sheet is interesting, and oddly similar to this one.

== git-email-based workflow ==

An e-mail-based workflow is preferred by many projects, including the Linux kernel.

 * [[https://blog.brixit.nl/git-email-flow-versus-github-flow/|Git email flow vs Github flow]]
 * [[https://git-send-email.io/|git-send-email.io]] helps you get up and running w/ git-email

See also: CodingStyle/Git

Workflow for gitorious and github

Initial checkout:

   1 # Fork repo on gitorious/github
   2 # Pull repo from gitorious/github
   3 # Add remote for upstream, e.g.
   4 cd Spoon-Knife
   5 git remote add upstream git://github.com/octocat/Spoon-Knife.git
   6 git fetch upstream

See Configuring a remote for a fork

When needing to merge upstream changes back into master:

   1 # Make sure we're in the branch we want to be in (i.e. master)
   2 git checkout master
   3 git fetch upstream
   4 # Merge from master branch of upstream into current branch
   5 git merge upstream/master

Cookbook

Delete remote branch

git push origin :name-of-remote-branch
# OR
git push origin --delete name-of-remote-branch

Reverting changes

Amend the previous commit that has not been propogated (i.e. undo it, then start a new one with the pending changes in the index):

git commit --amend -a -m "New commit message"

Undo a commit that has not been propagated:

git reset --soft HEAD^

just changes the repository without changing the files you've edited on disk. However:

git reset --hard HEAD^

will reset both repository and revert files.

Once a commit that has been propagated, there is no way to undo. However, the following will create a new commit undoing the previous commit's changes:

git revert HEAD

To only change a commit message for a commit that has not been propogated:

git commit --amend

Pull with rebase instead of merge

git pull --rebase

Configure a branch to always do a rebase instead of a merge:

git config branch.$BRANCH_NAME.rebase true

Enforce .gitignore

Remove files from the repository that should have been ignored by .gitignore:

git rm -r --cached .
git add .
git status
git commit -m ".gitignore is now working"

# Search commit log (i.e. messages) for given needle in all branches
git log --all --grep='needle'
# As above, but search reflog (much slower)
git log -g --grep='needle'
# Search contents of commits
git grep -F 'needle' $(git rev-list --all)
# Search contents of commit in a large repository
git rev-list --all | parallel -j4 -k -X git grep --color=always -F 'needle'
# Search branches (has problems)
git branch -a | tr -d \* | parallel -k git grep --color=always -iF 'needle'

Ignore whitespace bullshit

# Ignore white space when pulling or merging
git pull -Xignore-space-change
git merge -Xignore-space-change
git merge -Xignore-all-space

# Ignore white space changes when diff'ing
git diff --ignore-space-change

Rebase a branch

# Without having branch-you-want-to-rebase checked out
git rebase branch-you-want-to-rebase branch-to-rebase-from
# With having branch-you-want-to-rebase checked out
git checkout branch-you-want-to-rebase
git rebase branch-to-rebase-from

Rebase off a branch that itself had been rebased (keep the un-rebased branch around as old-branch-to-rebase-from):

git rebase --onto branch-to-rebase-from old-branch-to-rebase-from branch-you-want-to-rebase

If you want to rebase but get updated stamps (do this independently of reordering/merging commits with git rebase -i:

git rebase --ignore-date

Interactive rebase

Interactive rebase for only certain commits:

# Rebase only the last 2 commits
git rebase -i HEAD~2
# All commits that are on feature branch, but not on trunk branch
git rebase -i trunk

Problems

Cannot lock ref error

error: cannot lock ref 'refs/remotes/origin/bugfix/SPL-178301-lookups-cache-results-incorrectly':

is caused by your local repository's copy of the origin repository's branches getting corrupted. To fix:

git remote prune origin

It will not touch any of your local branches with your edits, or anything remote, just your local repo's knowledge of remote branches.

Per-repository user settings

git config user.name 'Samat K Jain'
git config user.email 'nobody@example.com'

Cleaning

# Discard all unstaged changes in CWD
git checkout -- .
# Remove untracked files and directories, dry run. `-n` for dry run.
git clean -df -n

GPG Signing

   1 # GPG sign all previous commits. Careful!
   2 git filter-branch -f --commit-filter 'git commit-tree -S "$KEY_ID"' HEAD

Submodules

In the below, TARGET_DIR is something like vendor/some-package.

Cloning a project w/ submodules

First clone:

git clone --recurse-submodules …

If you forgot --recurse-submodules, can run:

git submodule update --init --recursive

Adding submodules to a project

git submodule add $REPOSITORY_URL $TARGET_DIRECTORY

You need to start tracking the new .gitmodules file (just like .gitignore), as well as a "file" representing the submodule. git status will show it as $TARGET_DIRECTORY.

git add .gitmodules $TARGET_DIRECTORY
git commit -m 'Started tracking $REPOSITORY_URL as submodule'

Update submodules

Go to each submodule, fetch, and update:

git submodule update --remote --recursive
# git commit

Remove submodules

Go to each submodule, fetch, and update:

git submodule rm $TARGET_DIR
# git commit
# Completely remove submodule (will need to be init again if you go backwards in history) to save disk space
rm -Rf .git/modules/$TARGET_DIR

Will be done with a git pull automatically if submodule.recurse option is True.

Misc

Tell git to track a specific branch of a submodule, e.g. "master":

git config -f .gitmodules submodule.${TARGET_DIR}.branch master
# commit .gitmodules

-f is specified so that .gitmodule can be updated and other people using the repository can track the same branch. Omit this if you don't care.

Settings

# `--recursive` for everything but `git clone`
git config --global submodule.recurse true
# Show summary of submodule changes in `git status`
git config --global status.submodulesummary true
# Prettier diff for submodules
git config --global diff.submodule log

Interesting reading

The Git Parable: Describes building a system like git, from the ground-up

CIA's git tips & tricks sheet is interesting, and oddly similar to this one.

git-email-based workflow

An e-mail-based workflow is preferred by many projects, including the Linux kernel.


CategoryCheatSheet

SamatsWiki: CheatSheet/Git (last edited 2023-03-01 08:30:42 by SamatJain)