Deprecated - How to Remove Unwanted Files Before Merging an Upstream Branch to Master and Staging

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:

Image

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.

  1. [local repo] Switch to the principle branch, eg, 1.9.4.x and pull from upstream
  2. [local repo] Switch to prod
  3. [local repo] Launch Git Bash, run sh git-strip-merge <principle_branch>, eg, sh git-strip-merge 1.9.4.x
  4. [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

kiatng