Hi,

I'm trying to setup a workflow to track vendor releases (upstream).
Each new release are provided as an archive of source code, data,
documentation, etc.

For each vendor releases, fixes need to be applied before making them
available to users (downstream).

Seems to be a rather common use case, applied by most Linux distribution
for decades.

In my case, on top of each releases, a common set of patches will be applied,
the biggest, the most intrusive one, being converting CRLF to LF using dos2unix,
the others being small portability fixes. In this case, fixes are not going to
be applied by upstream.

I'm trying to "design" (copy ;) a workflow with following properties,
in order of importance:

1- I wish to keep a branch with each new vendor release as a commit.
   This branch's history is only about vendor releases,
   so it's easy to read the "changelog" of the vendor releases
   with command such as git log <vendor-release-branch>

2- I'd like to ease the process of applying our patches on top
   of each new vendor release, eg. reduces the likeliness of conflicts.

3- I wish to keep a branch with each new fixed vendor release as a commit.
   Just like the upstream <vendor-release-branch>, only one commit
   per release, so it's easy to read the "changelog" of the vendor releases
   with command such as git log <patched-release-branch>
   
(4- I wish nobody is going to think about ponies ...)

The workflow, as I tried to implement it is, can be described like this:
For each release, the new sources are imported in the upstream branch,
then the previous branch holding fixes is rebased against the updated
upstream branch, and finally, the updated fixes branch is merged in
the downstream branch.

Please find a diagram trying to explain the following workflow:

                           Input       Output

                             .     *(1)  .
                             .    / \    .
                             .   /   \   .
                             .  /     \  .
                             . /       \ .
                             ./         \.
                             /           \
Upstream release 1           |           |
                  \          v           |
                   --------->*           |
                             |\          |
                             | \         |
                             |  |        |
                             |  v        |
Upstream release 2           |  * fix 1  |
                  \          |   \       |
                   \         |    \      v
                    \        |     ----->*  Downstream release 1
                     \       v           |
                      ------>*           |
                             |\          |
                             | \         |
                             |  |        |
                             |  v        |
                             |  * fix 1' |
                             |  |        |
Upstream release 3           |  v        |
                  \          |  * fix 2' |
                   \         |   \       |
                    \        |    \      v
                     \       |     ----->* Downstream release 2
                      \      |           |
                       \     v           |
                        ---->*           |
                             |\          |
                             . \         |
                             |  |        |
                             .  v        |
                             .  * fix 1" |
                             |  |        |
                             .  v        |
                             .  * fix 2" |
                             .  |        |
                             |  v        |
                                * fix 3" |
                                 \       |
                                  \      v
                                   ----->* Downstream release 3
                                         |
                                         .
                                         |
                                         .
                                         .

(1) empty root commit

I hope someone would come with an easier workflow, more sustainable.
At least, please help me find flaws in this workflow, tell me where
I can found the documentation of others workflows achieving the same
results.

BTW while testing the workflow, I tried "git merge -s theirs"
and found it doesn't exist. I thought it would be available for
such a common use case. For each merge to the of the fixes branch
to the downstream branch, something like a whole new content is dropped
to the branch. The previous content is still needed but its only for history.
So I prefer to overwrite the content of the downstream branch, instead
of fixing each conflicts "manually" when using "git merge" with default
strategy and option.

In some article[1], I've found an explanation of the lack of
"git merge -s theirs", quoting maintainer opinion[2] regarding it.

[1] <http://www.seanius.net/blog/2011/02/git-merge-s-theirs/>
[2] <http://thread.gmane.org/gmane.comp.version-control.git/76650/focus=89024>

I was able to use "git merge --strategy=recursive --strategy-option=theirs" aka.
"git merge -X theirs". So I'm only frustrated to see my workflow not being
considered. But happy to be able to do it with "uncommon" options.


Appended here a script to reproduce the workflow described previously:

#! /bin/sh

set -e

GIT_AUTHOR_DATE=`date -R`
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"

export GIT_AUTHOR_DATE
export GIT_COMMITTER_DATE

# cleanup
rm -rf .git main.c

# prepare
git init
git commit --allow-empty -m "empty root commit"
git branch downstream master
git branch upstream master

#
# import first upstream release: v1
git checkout upstream
cat > main.c <<EOF

/* version string */
#define VERSION "1"

int
main(void)
{
    printf("version " VERSION);
}
EOF
git add main.c
git commit -m "Upstream release 1"

# apply fix on top of upstream release
# in an integration branch
git checkout -b upstream-1-fix upstream
cat > main.c <<EOF

/* version string */
#define VERSION "1"

int
main(void)
{
    printf("version " VERSION "\n");
}
EOF
git add main.c
git commit -m "Fix 1"

# make the "fixed" release available
# merge the integration branch
git checkout downstream
git merge --no-edit --no-ff upstream-1-fix
git tag downstream-default-1

#
# new upstream release: v2
git checkout upstream
cat > main.c <<EOF

/* version string */
#define VERSION "2"

int
main(void)
{
    printf("version " VERSION);
}
EOF
git add main.c
git commit -m "Upstream release 2"

# re-apply fix on top of new upstream release
# create a new integration branch to apply
# previous fix on top of the new release
git checkout -b upstream-2-fix upstream-1-fix
git rebase upstream
# apply a new fix
cat > main.c <<EOF

#include <stdio.h>

/* version string */
#define VERSION "2"

int
main(void)
{
    printf("version " VERSION "\n");
}
EOF
git add main.c
git commit -m "Fix 2"

# make the "fixed" release available
# merge the integration branch
git checkout downstream
git merge --no-edit --no-ff upstream-2-fix
git tag downstream-default-2

#
# new upstream release: v3
git checkout upstream
cat > main.c <<EOF

/* version string */
#define VERSION "3"
#define PACKAGE "foo"

int
main(void)
{
    printf("version " VERSION);
}
EOF
git add main.c
git commit -m "Upstream release 3"

# re-apply fixes on top of new upstream release
# create a new integration branch to apply
# previous fixes on top of the new release
git checkout -b upstream-3-fix upstream-2-fix
git rebase upstream
# apply a new fix
cat > main.c <<EOF

#include <stdio.h>

/* version string */
#define VERSION "3"
#define PACKAGE "foo"

int
main(void)
{
    printf("version " VERSION "\n");

    return 0;
}
EOF
git add main.c
git commit -m "Fix 3"

# make the "fixed" release available
# try to merge the integration branch
git checkout downstream
git merge --no-edit --no-ff upstream-3-fix || { 
echo "Merge failed, \"manually\" resolve conflict ..."
cat > main.c <<EOF

#include <stdio.h>

/* version string */
#define VERSION "3"
#define PACKAGE "foo"

int
main(void)
{
    printf("version " VERSION "\n");

    return 0;
}
EOF
git add main.c
git commit --no-edit
}
git tag downstream-default-3

# now, try a different merge strategy
git checkout master
git branch -D downstream
git branch downstream master

git checkout downstream

git merge --no-edit --no-ff --strategy-option theirs upstream-1-fix
git tag downstream-theirs-1
git merge --no-edit --no-ff --strategy-option theirs upstream-2-fix
git tag downstream-theirs-2
git merge --no-edit --no-ff --strategy-option theirs upstream-3-fix
git tag downstream-theirs-3

git checkout master

# "default" and "theirs" should match
# but have a different commit message:
# no conflict reported for "theirs"
git diff downstream-default-3 downstream-theirs-3


# Regards !

-- 
Yann Droneaud <ydrone...@opteya.com>
OPTEYA




--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to