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

Updated . Posted . Visible to the public.

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
Last edit
kiatng
Attachments
Posted by kiatng to Git (2019-11-13 06:46)