Deprecated method. Use this Show archive.org snapshot instead. See also this
For example, if we have an upstream remote from
magento-lts
Show archive.org snapshot
, and we have a master
branch for production, and staging
branch for staging server, and we do not want to merge files related to installation and sample files when we upgrade to a newer version from upstream.
What are remotes upstream & origin
upstream is the remote which is the owner of the repo. origin is our remote where we forked the repo from upstream. We can set this in TottoiseGit settings:
Step 1: Create 3 Files in Local Repo
List the files and directories to remove in a file
Create a file .gitstrip
in root:
app/etc/local.xml.additional
app/etc/local.xml.template
./dev/
./downloader/
./skin/install/
./var/package/
./.phpstorm.meta.php
./.htaccess.sample
./.travis.yml
./CODE_OF_CONDUCT.md
./composer.json
./index.php.sample
./install.php
./LICENSE_AFL.txt
./LICENSE.html
./LICENSE.txt
./php.ini.sample
README.md
RELEASE_NOTES.txt
The prefix ./
is optional.
Bash script to remove the files and directories
Create a file git-remove
in root:
#!/usr/bin/env bash
for fd in $(cat .gitstrip) ; do
fd=${fd//$'\r'}
([[ -f ${fd} ]] && git rm -f "${fd}") || ([[ -d ${fd} ]] && git rm -rf "${fd}")
done
The loop read each line from the file .gitstrip
and assign its string to var fd
.
fd=${fd//$'\r'}
does a string replacement to remove the trailing new line \r
character.
[[ -f ${fd} ]]
tests for file, if it's true
, run git rm -f "${fd}")
to git remove the file. If false
, continues after the ||
or operator.
[[ -d ${fd} ]]
tests for directory, if it's true
, run git rm -rf "${fd}")
to git remove recursively the directory. If false
, continues, which is do nothing.
Bash script to strip and merge
Create a file git-strip-merge
in root:
#!/usr/bin/env bash
#
# git-strip-merge - a git-merge that delete files on branch before merging
#
# Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not see <http://www.gnu.org/licenses/gpl.html>
#
# Answer for "How to setup a git driver to ignore a folder on merge?"
# See http://stackoverflow.com/questions/3111515
#Defaults:
msgcommit="remove files from '<branch>' before merge"
msgmerge="Merge stripped branch '<branch>'"
verbose=0
quiet=(--quiet)
usage() {
cat <<- USAGE
Usage: $myname [git-merge options] [-M <commitmsg>] <branch> FILE...
USAGE
if [[ "$1" ]] ; then
cat >&2 <<- USAGE
Try '$myname --help' for more information.
USAGE
exit 1
fi
cat <<-USAGE
git-merge that delete files on "foreign" <branch> before merging
Useful for ignoring a folder in <branch> before merging it with
current branch. Works by deleting FILE(S) in a detached commit based
on <branch>, and then performing the merge of this new commit in the
current branch. Note that <branch> is not changed by this procedure.
Also note that <branch> may actually be any reference, like a tag,
or a remote branch, or even a commit SHA.
For more information, see <http://stackoverflow.com/questions/3111515>
Options:
-h, --help
show this page.
-v, --verbose
do not use -q to suppress normal output of internal steps from git
checkout, rm, commit. By default, only git merge output is shown.
Errors, however, are never suppressed
-M <message>, --msgcommit=<message>
message for the removal commit in <branch>. Not to be confused
with the message of the merge commit, which is set by -m. Default
message is: "$msgcommit"
-m <message>, --message=<message>
message for the merge commit. Since we are not merging <branch>
directly, but rather a detached commit based on it, we forge a
message similar to git's default for a branch merge. Otherwise
git would use in message the full and ugly SHA1 of our commit.
Default message is: "$msgmerge"
For both commit messages, the token "<branch>" is replaced for the
actual <branch> name.
Additional options are passed unchecked to git merge.
All options must precede <branch> and FILE(s), except -h and --help
that may appear anywhere on the command line.
Example:
$myname design "photoshop/*"
Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>
USAGE
exit 0
}
# Helper functions
myname="${0##*/}"
argerr() { printf "%s: %s\n" "${0##*/}" "${1:-error}" >&2 ; usage 1 ; }
invalid() { argerr "invalid option: $1" ; }
missing() { argerr "missing ${2:+$2 }operand${1:+ from $1}." ; }
# Option handling
files=()
mergeopts=()
for arg in "$@"; do case "$arg" in -h|--help) usage ;; esac; done
while (( $# )); do
case "$1" in
-v|--verbose ) verbose=1 ;;
-M ) shift ; msgcommit=$1 ;;
-m ) shift ; msgmerge=$1 ;;
--msgcommit=* ) msgcommit=${1#*=} ;;
--message=* ) msgmerge=${1#*=} ;;
-* ) mergeopts+=( "$1" ) ;;
* ) branch="$1"
shift ; break ;;
esac
shift
done
files+=( "$@" )
# Argument handling
msgcommit=${msgcommit//<branch>/$branch}
msgmerge=${msgmerge//<branch>/$branch}
[[ "$msgcommit" ]] || missing "msgcommit" "MSG"
[[ "$branch" ]] || missing "" "<branch>"
[[ -f .gitstrip ]] || (( ${#files[@]} )) || missing "" "FILE"
((verbose)) && quiet=()
# Here the fun begins...
gitsha() { git rev-parse "$1" ; }
gitbranch() {
git symbolic-ref "$1" 2> /dev/null | sed 's/refs\/heads\///' ||
gitsha "$1"
}
gitrm() {
(( ${#files[@]} )) && git rm -rf "${files[@]}" "${quiet[@]}"
if [[ -f .gitstrip ]]; then
for fd in $(cat .gitstrip) ; do
fd=${fd//$'\r'}
([[ -f ${fd} ]] && git rm -f "${fd}" "${quiet[@]}") || ([[ -d ${fd} ]] && git rm -rf "${fd} "${quiet[@]}"")
done
fi
}
original=$(gitbranch HEAD)
branchsha=$(gitsha "$branch")
trap 'git checkout --quiet "$original"' EXIT
git checkout "$branchsha" "${quiet[@]}" &&
gitrm &&
git commit -m "$msgcommit" "${quiet[@]}" &&
newsha=$(gitsha HEAD) &&
git checkout "$original" "${quiet[@]}" &&
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha"
The above script is modified from https://github.com/MestreLion/git-tools/blob/master/git-strip-merge.
Step 2: Setup Branch prod
Add the files above in .gitignore
/app/etc/local.xml
.gitstrip
git-remove
git-strip-merge
Remove the files in .gitstrip
Launch Git Bash and run:
$ sh git-remove
Commit changes to a new branch prod
In TortoiseGit, commit changes to new branch prod and pushed to remote origin.
Now we have setup a prod branch. It is used for merging to our production master. We only need to do this once.
Step 3: Update prod Branch with the Latest Commits from upstream
We will use git-strip-merge
to update prod branch.
- [local repo] Switch to the principle branch, eg,
1.9.4.x
and pull from upstream - [local repo] Switch to prod
- [local repo] Launch Git Bash, run
sh git-strip-merge <principle_branch>
, eg,sh git-strip-merge 1.9.4.x
- [local repo] Push prod to upstream
Now we are ready to use prod to update our production master
Other Solutions
method 1 (only for untracked files in .gitignore)
Use git clean
. See Git: How to remove ignored files from your repository's directory. We can apply this in a separate forked of upstream's repo. Then we can pull from this forked repo to our local.
method 2
Use TortoiseGit to remove the unwanted files one by one. Then commit changes to a new branch prod
. Then, merge prod
to master
.
method 3
Alternatively, automate with a shell script: git-strip-merge Show archive.org snapshot