Okay, so now that I've actually done a couple of multi-branch commits...

I'm using the multiple-work-directory arrangement suggested on our wiki
page. The work flow seems to boil down to:

* Prepare patch in master
* Stage patch with git add
* git diff --staged >/tmp/patch-head
* cd into REL9_0_STABLE workdir
* patch -p0 </tmp/patch-head
* Adjust patch if needed
* Stage patch with git add
* git diff --staged >/tmp/patch-90
* cd into REL8_4_STABLE workdir
* patch -p0 </tmp/patch-90
* ... lather, rinse, repeat ...
* cd back to master
* git commit -F /tmp/commitmsg
* cd into REL9_0_STABLE workdir
* git commit -F /tmp/commitmsg
* cd into REL8_4_STABLE workdir
* git commit -F /tmp/commitmsg
* ... lather, rinse, repeat ...
* git push

While this isn't much worse than what I was used to with CVS, it's
definitely not better. I think that I could simplify transferring the
patch back to older branches if I could use git cherry-pick. However,
that only works on already-committed patches. If I commit in master
before I start working on 9.0, and so on back, then the commits will be
separated in time by a significant amount, thus destroying any chance of
having git_topo_order recognize them as related. So we're back up
against the problem of git not really understanding the relationships of
patches in different branches.

One idea that comes to me is to do each patch in a temporary side branch
off that maintenance branch, and then only the final commits merging
that work back to the public branches need be closely spaced. But being
still a git novice, it's not exactly clear to me how to do that, and
anyway it seems like there's still possibility for trouble if there's
unexpected merging failures on some of the branches. (That would only
be an issue if the back-patching took long enough for some of the
branches to change underneath me, which isn't too likely, but if it
did happen how do I recover and still keep the commits close together?)

So it seems like maybe we still need some more thought about how to
recognize related commits in different branches. Or at the very least,
we need a best-practice document explaining how to manage this --- we
shouldn't expect every committer to reinvent this wheel for himself.

Comments?

regards, tom lane

Search Discussions

  • Andrew Dunstan at Sep 22, 2010 at 2:12 am

    On 09/21/2010 09:20 PM, Tom Lane wrote:
    Okay, so now that I've actually done a couple of multi-branch commits...

    I'm using the multiple-work-directory arrangement suggested on our wiki
    page. The work flow seems to boil down to:

    * Prepare patch in master
    * Stage patch with git add
    * git diff --staged>/tmp/patch-head
    * cd into REL9_0_STABLE workdir
    * patch -p0</tmp/patch-head
    * Adjust patch if needed
    * Stage patch with git add
    * git diff --staged>/tmp/patch-90
    * cd into REL8_4_STABLE workdir
    * patch -p0</tmp/patch-90
    * ... lather, rinse, repeat ...
    * cd back to master
    * git commit -F /tmp/commitmsg
    * cd into REL9_0_STABLE workdir
    * git commit -F /tmp/commitmsg
    * cd into REL8_4_STABLE workdir
    * git commit -F /tmp/commitmsg
    * ... lather, rinse, repeat ...
    * git push

    While this isn't much worse than what I was used to with CVS, it's
    definitely not better. I think that I could simplify transferring the
    patch back to older branches if I could use git cherry-pick. However,
    that only works on already-committed patches. If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related. So we're back up
    against the problem of git not really understanding the relationships of
    patches in different branches.

    One idea that comes to me is to do each patch in a temporary side branch
    off that maintenance branch, and then only the final commits merging
    that work back to the public branches need be closely spaced. But being
    still a git novice, it's not exactly clear to me how to do that, and
    anyway it seems like there's still possibility for trouble if there's
    unexpected merging failures on some of the branches. (That would only
    be an issue if the back-patching took long enough for some of the
    branches to change underneath me, which isn't too likely, but if it
    did happen how do I recover and still keep the commits close together?)
    I suspect you should indeed be working on topic branches for everything
    non-trivial. You can safely commit on them, cherry-pick from them,
    squash from them onto the main branch, and then discard them. You can
    resolve problems before committing on the main branch by doing:

    git checkout mainbranch
    git merge --squash --no-commit topicbranch

    Unless I'm missing something there's no reason you should ever have to
    have a significant delay between branches in commits/pushes.

    I know git has something of a learning curve, but I'm betting that in a
    month or so you'll be better at using it than most of us ;-)

    cheers

    andrew
  • David E. Wheeler at Sep 22, 2010 at 2:17 am

    On Sep 21, 2010, at 6:20 PM, Tom Lane wrote:

    While this isn't much worse than what I was used to with CVS, it's
    definitely not better. I think that I could simplify transferring the
    patch back to older branches if I could use git cherry-pick. However,
    that only works on already-committed patches. If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related. So we're back up
    against the problem of git not really understanding the relationships of
    patches in different branches.
    You could commit in each one as you go, cherry-pick, and then in each one

    git reset --soft HEAD^

    Then they'd all be patched and staged.

    Best,

    David
  • Bruce Momjian at Sep 22, 2010 at 3:01 am

    David E. Wheeler wrote:
    On Sep 21, 2010, at 6:20 PM, Tom Lane wrote:

    While this isn't much worse than what I was used to with CVS, it's
    definitely not better. I think that I could simplify transferring the
    patch back to older branches if I could use git cherry-pick. However,
    that only works on already-committed patches. If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related. So we're back up
    against the problem of git not really understanding the relationships of
    patches in different branches.
    You could commit in each one as you go, cherry-pick, and then in each one

    git reset --soft HEAD^

    Then they'd all be patched and staged.
    If I understand correctly, that 'git reset' will mark all branch changes
    as staged but not committed, and then you can commit all branches at
    once and push it. Is that right?

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • David E. Wheeler at Sep 22, 2010 at 3:03 am

    On Sep 21, 2010, at 8:01 PM, Bruce Momjian wrote:

    Then they'd all be patched and staged.
    If I understand correctly, that 'git reset' will mark all branch changes
    as staged but not committed, and then you can commit all branches at
    once and push it. Is that right?
    Right.

    David
  • Bruce Momjian at Sep 22, 2010 at 3:07 am

    David E. Wheeler wrote:
    On Sep 21, 2010, at 8:01 PM, Bruce Momjian wrote:

    Then they'd all be patched and staged.
    If I understand correctly, that 'git reset' will mark all branch changes
    as staged but not committed, and then you can commit all branches at
    once and push it. Is that right?
    Right.
    OK, I am scared I actually understood that. ;-)

    Is there a command to commit all stated changes in all branches or do we
    have to go around to each branch to do the commit on each one? I
    realize the push works to push all branch commits (or it only do that
    from the master branch?).

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Tom Lane at Sep 22, 2010 at 3:19 am

    "David E. Wheeler" <david@kineticode.com> writes:
    On Sep 21, 2010, at 8:01 PM, Bruce Momjian wrote:
    Then they'd all be patched and staged.
    If I understand correctly, that 'git reset' will mark all branch changes
    as staged but not committed, and then you can commit all branches at
    once and push it. Is that right?
    Right.
    You sure about the "staged" part? If I'm reading the git-reset man
    page correctly, this command will revert your commit position and index,
    leaving only the modified work files behind. So it looks to me like
    you need another round of git add, or at least git commit -a.

    Offhand I think I like Andrew's recommendation of a shortlived branch
    better. In essence your idea is using the tip of "master" itself as a
    shortlived branch, which is maybe a bit too cute. If you get distracted
    and need to do something else for awhile, the tip of "master" is not
    where you want your not-yet-pushable work to be.

    (For those following along at home, there are some mighty instructive
    examples in the git-reset man page.)

    regards, tom lane
  • Bruce Momjian at Sep 22, 2010 at 3:30 am

    Tom Lane wrote:
    "David E. Wheeler" <david@kineticode.com> writes:
    On Sep 21, 2010, at 8:01 PM, Bruce Momjian wrote:
    Then they'd all be patched and staged.
    If I understand correctly, that 'git reset' will mark all branch changes
    as staged but not committed, and then you can commit all branches at
    once and push it. Is that right?
    Right.
    You sure about the "staged" part? If I'm reading the git-reset man
    page correctly, this command will revert your commit position and index,
    leaving only the modified work files behind. So it looks to me like
    you need another round of git add, or at least git commit -a.
    The command was:

    git reset --soft HEAD^

    The --soft says:

    --soft
    Does not touch the index file nor the working tree
    at all, but requires them to be in a good order.
    This leaves all your changed files "Changes to be
    committed", as git status would put it.

    and the HEAD^ is the same as HEAD^1, which is on commit backward from
    HEAD. I assume ""Changes to be committed" means "staged".
    Offhand I think I like Andrew's recommendation of a shortlived branch
    better. In essence your idea is using the tip of "master" itself as a
    shortlived branch, which is maybe a bit too cute. If you get distracted
    True.

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Bruce Momjian at Sep 22, 2010 at 3:32 am

    Bruce Momjian wrote:
    Offhand I think I like Andrew's recommendation of a shortlived branch
    better. In essence your idea is using the tip of "master" itself as a
    shortlived branch, which is maybe a bit too cute. If you get distracted
    True.
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Tom Lane at Sep 22, 2010 at 3:47 am

    Bruce Momjian writes:
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.
    Monkey-work is scriptable though. It'll all be worth it if git
    cherry-pick is even marginally smarter about back-merging the actual
    patches. In principle it could be less easily confused than plain
    old patch, but I was a bit discouraged by the upthread comment that
    it's just a shorthand for "git diff | patch" :-(

    regards, tom lane
  • Elvis Pranskevichus at Sep 22, 2010 at 5:50 am

    On September 21, 2010 11:47:30 pm Tom Lane wrote:
    Bruce Momjian <bruce@momjian.us> writes:
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.
    Monkey-work is scriptable though. It'll all be worth it if git
    cherry-pick is even marginally smarter about back-merging the actual
    patches. In principle it could be less easily confused than plain
    old patch, but I was a bit discouraged by the upthread comment that
    it's just a shorthand for "git diff | patch" :-(

    regards, tom lane

    cherry-pick is NOT just a shorthand for git diff | patch. It is a single-
    commit merge tool. man page does not indicate that, but you can supply the
    merge strategy parameter, just like you would do with git merge, but AFAIR
    it's not necessary and cherry-pick will fallback to the default recursive
    merge when needed.

    Elvis
  • Magnus Hagander at Sep 22, 2010 at 11:08 am

    On Wed, Sep 22, 2010 at 05:47, Tom Lane wrote:
    Bruce Momjian <bruce@momjian.us> writes:
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.
    Monkey-work is scriptable though.  It'll all be worth it if git
    cherry-pick is even marginally smarter about back-merging the actual
    patches.  In principle it could be less easily confused than plain
    old patch, but I was a bit discouraged by the upthread comment that
    it's just a shorthand for "git diff | patch" :-(
    FWIW, here's the workflow I just tried for the gitignore patch (blame
    me and not the workflow if I broke the patch, btw :P)



    * Have a master "committers" repo, with all active branches checked out
    (and a simple script that updates and can reset them all automatically)
    * Have a working repo, where I do my changes. Each branch gets a checkout
    when necessary here, and this is where I apply it. I've just used
    inline checkouts,
    but I don't see why it shouldn't work with workdirs etc.
    * In the working repo, apply patch to master branch.
    * Then use git cherry-pick to get it into the back branches (still in
    the working repo)
    At this point, also do the testing of the backpatch.

    At this point we have commits with potentially lots of time in between them.
    So now we squash these onto the committers repository, using a small script that
    does this:


    #!/bin/sh

    set -e

    CMSG=/tmp/commitmsg.$$

    editor $CMSG

    if [ ! -f $CMSG ]; then
    echo No commit message, aborting.
    exit 0
    fi

    export BRANCHES="master REL9_0_STABLE REL8_4_STABLE REL8_3_STABLE
    REL8_2_STABLE REL8_1_STABLE REL8_0_STABLE REL7_4_STABLE"

    echo Fetching local changes so they are available to merge
    git fetch local

    for B in ${BRANCHES} ; do
    echo Switching and merging $B...
    git checkout $B
    git merge --squash local/$B --no-commit
    git commit -F $CMSG
    done

    rm -f $CMSG



    BTW, before pushing, I like to do something like this:

    git push --dry-run 2>&1 |egrep -v "^To" | awk '{print $1}'|xargs git
    log --format=fuller

    just to get a list of exactly what I'm about to push :-) That doesn't
    mean there won't
    be mistake, but maybe fewer of them...
  • Andrew Dunstan at Sep 22, 2010 at 11:47 am

    On 09/22/2010 07:07 AM, Magnus Hagander wrote:
    On Wed, Sep 22, 2010 at 05:47, Tom Lanewrote:
    Bruce Momjian<bruce@momjian.us> writes:
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.
    Monkey-work is scriptable though. It'll all be worth it if git
    cherry-pick is even marginally smarter about back-merging the actual
    patches. In principle it could be less easily confused than plain
    old patch, but I was a bit discouraged by the upthread comment that
    it's just a shorthand for "git diff | patch" :-(
    FWIW, here's the workflow I just tried for the gitignore patch (blame
    me and not the workflow if I broke the patch, btw :P)



    * Have a master "committers" repo, with all active branches checked out
    (and a simple script that updates and can reset them all automatically)
    * Have a working repo, where I do my changes. Each branch gets a checkout
    when necessary here, and this is where I apply it. I've just used
    inline checkouts,
    but I don't see why it shouldn't work with workdirs etc.
    * In the working repo, apply patch to master branch.
    * Then use git cherry-pick to get it into the back branches (still in
    the working repo)
    At this point, also do the testing of the backpatch.

    At this point we have commits with potentially lots of time in between them.
    So now we squash these onto the committers repository, using a small script that
    does this:


    #!/bin/sh

    set -e

    CMSG=/tmp/commitmsg.$$

    editor $CMSG

    if [ ! -f $CMSG ]; then
    echo No commit message, aborting.
    exit 0
    fi

    export BRANCHES="master REL9_0_STABLE REL8_4_STABLE REL8_3_STABLE
    REL8_2_STABLE REL8_1_STABLE REL8_0_STABLE REL7_4_STABLE"

    echo Fetching local changes so they are available to merge
    git fetch local

    for B in ${BRANCHES} ; do
    echo Switching and merging $B...
    git checkout $B
    git merge --squash local/$B --no-commit
    git commit -F $CMSG
    done

    rm -f $CMSG



    BTW, before pushing, I like to do something like this:

    git push --dry-run 2>&1 |egrep -v "^To" | awk '{print $1}'|xargs git
    log --format=fuller

    just to get a list of exactly what I'm about to push :-) That doesn't
    mean there won't
    be mistake, but maybe fewer of them...

    What a rigmarole! This seems to be getting positively gothic.

    cheers

    andrew
  • Magnus Hagander at Sep 22, 2010 at 11:48 am

    On Wed, Sep 22, 2010 at 13:47, Andrew Dunstan wrote:
    On 09/22/2010 07:07 AM, Magnus Hagander wrote:

    On Wed, Sep 22, 2010 at 05:47, Tom Lanewrote:
    Bruce Momjian<bruce@momjian.us>  writes:
    However, keep in mind that creating a branch in every existing backpatch
    branch is going to create even more backpatching monkey-work.
    Monkey-work is scriptable though.  It'll all be worth it if git
    cherry-pick is even marginally smarter about back-merging the actual
    patches.  In principle it could be less easily confused than plain
    old patch, but I was a bit discouraged by the upthread comment that
    it's just a shorthand for "git diff | patch" :-(
    FWIW, here's the workflow I just tried for the gitignore patch (blame
    me and not the workflow if I broke the patch, btw :P)



    * Have a master "committers" repo, with all active branches checked out
    (and a simple script that updates and can reset them all automatically)
    * Have a working repo, where I do my changes. Each branch gets a checkout
    when necessary here, and this is where I apply it. I've just used
    inline checkouts,
    but I don't see why it shouldn't work with workdirs etc.
    * In the working repo, apply patch to master branch.
    * Then use git cherry-pick to get it into the back branches (still in
    the working repo)
    At this point, also do the testing of the backpatch.

    At this point we have commits with potentially lots of time in between
    them.
    So now we squash these onto the committers repository, using a small
    script that
    does this:


    #!/bin/sh

    set -e

    CMSG=/tmp/commitmsg.$$

    editor $CMSG

    if [ ! -f $CMSG ]; then
    echo No commit message, aborting.
    exit 0
    fi

    export BRANCHES="master REL9_0_STABLE REL8_4_STABLE REL8_3_STABLE
    REL8_2_STABLE REL8_1_STABLE REL8_0_STABLE REL7_4_STABLE"

    echo Fetching local changes so they are available to merge
    git fetch local

    for B in ${BRANCHES} ; do
    echo Switching and merging $B...
    git checkout $B
    git merge --squash local/$B --no-commit
    git commit -F $CMSG
    done

    rm -f $CMSG



    BTW, before pushing, I like to do something like this:

    git push --dry-run 2>&1 |egrep -v "^To" | awk '{print $1}'|xargs git
    log --format=fuller

    just to get a list of exactly what I'm about to push :-) That doesn't
    mean there won't
    be mistake, but maybe fewer of them...

    What a rigmarole! This seems to be getting positively gothic.
    FWIW, it's shorter and simpler than what I use for cvs ;) But maybe
    that's because I'm being overly careful...
  • A.M. at Sep 22, 2010 at 3:53 am

    On Sep 21, 2010, at 11:19 PM, Tom Lane wrote:

    Offhand I think I like Andrew's recommendation of a shortlived branch
    better. In essence your idea is using the tip of "master" itself as a
    shortlived branch, which is maybe a bit too cute. If you get distracted
    and need to do something else for awhile, the tip of "master" is not
    where you want your not-yet-pushable work to be.
    For uncommitted work, see also "git stash".
    http://www.kernel.org/pub/software/scm/git/docs/git-stash.html

    Cheers,
    M
  • David E. Wheeler at Sep 22, 2010 at 4:46 am

    On Sep 21, 2010, at 8:19 PM, Tom Lane wrote:

    You sure about the "staged" part?
    Yes, I do it all the time (I make a lot of mistakes).
    Offhand I think I like Andrew's recommendation of a shortlived branch
    better. In essence your idea is using the tip of "master" itself as a
    shortlived branch, which is maybe a bit too cute. If you get distracted
    and need to do something else for awhile, the tip of "master" is not
    where you want your not-yet-pushable work to be.
    Yes, I think using branches for everything is generally the way to go. But if you wanted to just use your existing approach, then reset --soft HEAD^ would work, too.

    Best,

    David
  • David Christensen at Sep 22, 2010 at 3:03 am

    If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related. So we're back up
    against the problem of git not really understanding the relationships of
    patches in different branches.

    Is the issue here the clock time spent between the commits, i.e., the possibility that someone is going to push to the specific branches in between or the date/time that the commit itself displays? Because if it's specifically commit time that's at issue, I believe `git cherry-pick` preserves the original commit time from the original commit, which should make that a non-issue. Even if you need to fix up a commit to get the cherry-pick to apply, you can always `git commit -C <ref-of-cherry-pick>` to preserve the authorship/commit time for the commit in question.

    Regards,

    David
    --
    David Christensen
    End Point Corporation
    david@endpoint.com
  • Bruce Momjian at Sep 22, 2010 at 3:05 am

    David Christensen wrote:
    If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related. So we're back up
    against the problem of git not really understanding the relationships of
    patches in different branches.

    Is the issue here the clock time spent between the commits, i.e., the
    possibility that someone is going to push to the specific branches in
    between or the date/time that the commit itself displays? Because if
    it's specifically commit time that's at issue, I believe `git
    cherry-pick` preserves the original commit time from the original
    commit, which should make that a non-issue. Even if you need to fix
    up a commit to get the cherry-pick to apply, you can always `git commit
    -C <ref-of-cherry-pick>` to preserve the authorship/commit time for
    the commit in question.
    The problem is that the cherrypicks will often have to modified, and it
    can take +20 minutes to resolve some of them.

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Tom Lane at Sep 22, 2010 at 3:35 am

    Bruce Momjian writes:
    The problem is that the cherrypicks will often have to modified, and it
    can take +20 minutes to resolve some of them.
    To say nothing of actually *testing* the patch in each branch, which is
    Strongly Recommended if it didn't apply cleanly. I've not infrequently
    spent many hours on a difficult back-patch sequence.

    regards, tom lane
  • Tom Lane at Sep 22, 2010 at 3:32 am

    David Christensen writes:
    Is the issue here the clock time spent between the commits, i.e., the possibility that someone is going to push to the specific branches in between or the date/time that the commit itself displays? Because if it's specifically commit time that's at issue, I believe `git cherry-pick` preserves the original commit time from the original commit, which should make that a non-issue. Even if you need to fix up a commit to get the cherry-pick to apply, you can always `git commit -C <ref-of-cherry-pick>` to preserve the authorship/commit time for the commit in question.
    Oh, yeah, that's interesting. So you could force all the commits to
    match the timestamp of the first one. That's sort of the wrong end
    of the process though --- I'd rather have a timestamp closer to when
    I'm done than when I start.

    The other thing that comes to mind on further reflection is that by
    the time you get done with the back-patching, the commit log message
    might be different from what you thought it would be when you started.
    I had an example just today:
    http://git.postgresql.org/gitweb?p=postgresql.git;a=commit;h=829f5b3571241cae2cc1a02923439cd0725d683c
    Fixing "make distdir" wasn't part of what I was doing when I started.
    I suppose I could have done that in a separate series of commits, but
    if the idea is to make things more efficient not less so, that's not
    the direction I want to go.

    So right now I'm thinking that the best approach is to do the work
    in temporary topic branches, then make up a commit message and use
    it while doing squash merges onto the public branches. I hadn't thought
    when I went into this that a two-line patch would justify a temporary
    branch, but if you need to back-patch it, maybe it does.

    In principle I guess that we could decide to use -c or -C for the squash
    merges and thus make their commit timestamps exactly the same not only
    approximately the same. This seems a bit overly anal retentive to me
    at the moment, but maybe sometime in the future it'll be an idea worth
    adopting.

    regards, tom lane
  • Heikki Linnakangas at Sep 22, 2010 at 5:39 am

    On 22/09/10 04:20, Tom Lane wrote:
    Okay, so now that I've actually done a couple of multi-branch commits...

    I'm using the multiple-work-directory arrangement suggested on our wiki
    page. The work flow seems to boil down to:

    * Prepare patch in master
    * Stage patch with git add
    * git diff --staged>/tmp/patch-head
    * cd into REL9_0_STABLE workdir
    * patch -p0</tmp/patch-head
    * Adjust patch if needed
    * Stage patch with git add
    * git diff --staged>/tmp/patch-90
    * cd into REL8_4_STABLE workdir
    * patch -p0</tmp/patch-90
    * ... lather, rinse, repeat ...
    * cd back to master
    * git commit -F /tmp/commitmsg
    * cd into REL9_0_STABLE workdir
    * git commit -F /tmp/commitmsg
    * cd into REL8_4_STABLE workdir
    * git commit -F /tmp/commitmsg
    * ... lather, rinse, repeat ...
    * git push

    While this isn't much worse than what I was used to with CVS, it's
    definitely not better. I think that I could simplify transferring the
    patch back to older branches if I could use git cherry-pick. However,
    that only works on already-committed patches. If I commit in master
    before I start working on 9.0, and so on back, then the commits will be
    separated in time by a significant amount, thus destroying any chance of
    having git_topo_order recognize them as related.
    In git, each commit has two timestamps. Author timestamp and committer
    timestamp. They are usually the same, but when you cherry-pick, the
    cherry-picked commit retains the original author timestamp, while commit
    timestamp changes. "git log" shows only the author timestamp, and if I'm
    reading git_topo_order correctly, that's what it cares about too. "git
    log --format=fuller" can be used to show both.

    So AFAICS, if you use cherry-pick, you're fine. Even if you don't for
    some reason, you can override the author timestamp with "git commit
    --date=<date>".

    --
    Heikki Linnakangas
    EnterpriseDB http://www.enterprisedb.com
  • Abhijit Menon-Sen at Sep 22, 2010 at 10:44 am

    At 2010-09-21 21:20:06 -0400, tgl@sss.pgh.pa.us wrote:
    So it seems like maybe we still need some more thought about how to
    recognize related commits in different branches.
    I'd suggest using "git cherry-pick -x" (or something similar) to mark
    backported patches:

    -x When recording the commit, append to the original commit message
    a note that indicates which commit this change was cherry-picked
    from. Append the note only for cherry picks without conflicts.
    Do not use this option if you are cherry-picking from your
    private branch because the information is useless to the
    recipient. If on the other hand you are cherry-picking between
    two publicly visible branches (e.g. backporting a fix to a
    maintenance branch for an older release from a development
    branch), adding this information can be useful.

    I don't think it makes any sense to contort your workflow to commit to
    different branches at the same instant just to be able to group commits
    by timestamp. Using the trail left by cherry-pick -x is much better. You
    can just commit your changes to master and cherry-pick them wherever you
    want to. This is independent of doing the work in a topic branch.

    (Of course, with git it's less troublesome to merge forward rather than
    pick backwards, but that's a workflow change that's a lot harder to
    adjust to.)

    -- ams
  • Robert Haas at Sep 22, 2010 at 1:20 pm

    On Tue, Sep 21, 2010 at 9:20 PM, Tom Lane wrote:
    So it seems like maybe we still need some more thought about how to
    recognize related commits in different branches.  Or at the very least,
    we need a best-practice document explaining how to manage this --- we
    shouldn't expect every committer to reinvent this wheel for himself.

    Comments?
    I don't think there's one right way to do this. In fact, there are
    probably at least 50 reasonable ways to do it, depending on your own
    workflow preferences. And you needn't do it the same way every time,
    either. I don't. git is designed to treat commits the way that
    databases treat rows. They are objects. You can create them, throw
    them out, move them around, replace them with updated versions, etc.
    And there are multiple ways of doing each of these things (just as
    there's no single right way to design a database schema). Of course,
    in the One True Source Tree, we only every create them at the heads of
    existing branches. But in your own workspace, you can do all of those
    things - and you should, because they make you able to get the same
    things done faster.

    What I plan to do, I think, is use one clone nearly all the time. If
    I need to back-patch, I'll switch branches and either apply from the
    stash or cherry-pick off the master. But if I need to to go back more
    than one or two branches and there are merge conflicts, I'll create a
    bunch of temporary clones off my main clone and push/pull from there.
    Then I'll remove them when I'm done. But from what I gather, there
    are probably going to be at least as many workflows as there are
    committers, and maybe more, since I just said I'm going to use two
    different approaches depending on the situation.

    One option is just to update the date stamp on each commit before you
    push. You could check out each branch you've updated and do something
    like:

    GIT_EDITOR=/usr/bin/true git commit --amend --date=now

    Of course that'll only update the top commit, and you want to be sure
    not to do it on branches where the top commit is something that's
    already been pushed. But to reiterate my main point, I think we
    should only dictate the contents of the commits that must be pushed
    (e.g. time stamps close together, so git_topo_order can match them up)
    and not the process by which someone creates those commits (because
    the chances of getting more than 1 person to agree on the way to
    generate such commits seems near zero, and the fact that I plan to do
    it different ways depending on the situation means that even getting 1
    person to agree with themselves on how to do it may be out of reach).

    People have repeatedly suggested that timestamp/author/log message
    matching is a lousy way of matching up commits. I agree, but we have
    14.25 years of history for which that's the only practical method. We
    could decide on a different method going forward, such as embedding a
    token (the format of which we can argue about until we're blue in the
    face - could be whatever git cherry-pick does or could be a reference
    to our issue tracking system if we had one, could be something else)
    in each commit in a very specific format which a script can then
    recognize. The advantage of that is that it might feel a bit less ad
    hoc than what we're doing now; the disadvantage is that then our
    scripts would have to know about both methods, unless of course we go
    back and annotate all of the old commits (using git-notes) with
    reconstructed information on which commits go together, which we
    already have from git_topo_order. No matter what we pick, it's going
    to require non-zero effort to not screw it up; and with the exception
    of doing forward merges which I think is a terrible idea, none of the
    methods so far proposed seem likely to take significantly more time
    than any of the others. So if we're going to change anything at all,
    we ought to focus on how it's going to improve the overall way that we
    manage the project, not on the exact sequence of commands that will be
    required to create it, which I'm fairly confident will settle down to
    a quite small number as you and everyone else get used to the new tool
    (but it won't be the same sequence for everyone).

    --
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise Postgres Company
  • Bruce Momjian at Sep 22, 2010 at 1:24 pm

    Tom Lane wrote:
    Okay, so now that I've actually done a couple of multi-branch commits...

    I'm using the multiple-work-directory arrangement suggested on our wiki
    page. The work flow seems to boil down to:

    * Prepare patch in master
    * Stage patch with git add
    * git diff --staged >/tmp/patch-head
    * cd into REL9_0_STABLE workdir
    * patch -p0 </tmp/patch-head
    * Adjust patch if needed
    * Stage patch with git add
    * git diff --staged >/tmp/patch-90
    * cd into REL8_4_STABLE workdir
    * patch -p0 </tmp/patch-90
    * ... lather, rinse, repeat ...
    * cd back to master
    * git commit -F /tmp/commitmsg
    * cd into REL9_0_STABLE workdir
    * git commit -F /tmp/commitmsg
    * cd into REL8_4_STABLE workdir
    * git commit -F /tmp/commitmsg
    * ... lather, rinse, repeat ...
    * git push
    Uh, just to be clear, the above is more complex than necessary because
    git diff will show all uncommitted modifications. You could just do:
    * Prepare patch in master
    * git diff >/tmp/patch-head
    * cd into REL9_0_STABLE workdir
    * patch -p0 </tmp/patch-head
    * Adjust patch if needed
    ...

    There is no need for 'git add' because once you are done you can use git
    commmit -a in each branch to add all modifications and commit them. I
    think this exactly matches how we did thing with CVS. A final 'git
    push' sends them to the remote repository. This causes commits to all
    happen around the same time.

    I am not saying that is the way we should to it, but it is clearly
    possible.

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Tom Lane at Sep 22, 2010 at 2:01 pm

    Bruce Momjian writes:
    There is no need for 'git add' because once you are done you can use git
    commmit -a in each branch to add all modifications and commit them.
    git commit -a is not a universal solution. In particular, the patch
    I was dealing with yesterday involved additions and removals of files,
    neither of which will be implemented by git commit -a.

    regards, tom lane
  • Bruce Momjian at Sep 22, 2010 at 4:40 pm

    Tom Lane wrote:
    Bruce Momjian <bruce@momjian.us> writes:
    There is no need for 'git add' because once you are done you can use git
    commmit -a in each branch to add all modifications and commit them.
    git commit -a is not a universal solution. In particular, the patch
    I was dealing with yesterday involved additions and removals of files,
    neither of which will be implemented by git commit -a.
    Uh, why is that? I see -a saying:

    -a, --all
    Tell the command to automatically stage files that
    have been modified and deleted, but new files you have
    not told git about are not affected.

    What is it about add/deletes that it doesn't do? Is the problem 'git
    add' creates a stage already? How is that a problem?

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +
  • Robert Haas at Sep 22, 2010 at 4:48 pm

    On Wed, Sep 22, 2010 at 12:40 PM, Bruce Momjian wrote:
    Tom Lane wrote:
    Bruce Momjian <bruce@momjian.us> writes:
    There is no need for 'git add' because once you are done you can use git
    commmit -a in each branch to add all modifications and commit them.
    git commit -a is not a universal solution.  In particular, the patch
    I was dealing with yesterday involved additions and removals of files,
    neither of which will be implemented by git commit -a.
    Uh, why is that?  I see -a saying:

    -a, --all
    Tell the command to automatically stage files that
    have been modified and deleted, but new files you have
    not told git about are not affected.

    What is it about add/deletes that it doesn't do?  Is the problem 'git
    add' creates a stage already?  How is that a problem?
    Tom is slightly incorrect. Deletions work fine with git commit -a.
    git already knows about the files, so everything just works. However,
    it won't pick up on added files, because it can't distinguish between
    a file that you want added to the repository and a stray file you left
    lying around and assumes the latter. But I don't see that this takes
    anything away from your point. You can certainly just work on the
    patch in each repository separately and then commit everything all at
    once at the end, if you're so inclined. Of course, as Tom points out,
    it's a lot nicer to apply patches in a way that allows git to try to
    auto-merge for you. Sometimes it works, and when it doesn't work
    having the merge conflict stuff in the file is still better than
    having a .rej hunk leftover that you have to figure out what to do
    with. So personally I don't intend to do it that way, but as Larry
    Wall said about Perl, There's More Than One Way To Do It.

    --
    Robert Haas
    EnterpriseDB: http://www.enterprisedb.com
    The Enterprise Postgres Company
  • Bruce Momjian at Sep 22, 2010 at 4:52 pm

    Robert Haas wrote:
    What is it about add/deletes that it doesn't do? ?Is the problem 'git
    add' creates a stage already? ?How is that a problem?
    Tom is slightly incorrect. Deletions work fine with git commit -a.
    git already knows about the files, so everything just works. However,
    it won't pick up on added files, because it can't distinguish between
    a file that you want added to the repository and a stray file you left
    lying around and assumes the latter. But I don't see that this takes
    anything away from your point. You can certainly just work on the
    OK, so I just somehow made a valid git suggestion. I think I need to
    lay down. :-O
    patch in each repository separately and then commit everything all at
    once at the end, if you're so inclined. Of course, as Tom points out,
    it's a lot nicer to apply patches in a way that allows git to try to
    auto-merge for you. Sometimes it works, and when it doesn't work
    having the merge conflict stuff in the file is still better than
    having a .rej hunk leftover that you have to figure out what to do
    with. So personally I don't intend to do it that way, but as Larry
    Wall said about Perl, There's More Than One Way To Do It.
    My back-patches are usually super-simple (everyone laughs) so my patch
    files are trival to apply.

    --
    Bruce Momjian <bruce@momjian.us> http://momjian.us
    EnterpriseDB http://enterprisedb.com

    + It's impossible for everything to be true. +

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppgsql-hackers @
categoriespostgresql
postedSep 22, '10 at 1:20a
activeSep 22, '10 at 4:52p
posts28
users11
websitepostgresql.org...
irc#postgresql

People

Translate

site design / logo © 2022 Grokbase