git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Is there a way to exclude user-specified files or directories from participating in merges?

From
Junio C Hamano <gitster@pobox.com>
Date
Feb 18, 2009, 01:36 UTC
Message-ID
<7vmyck1q7i.fsf@gitster.siamese.dyndns.org>
In-Reply-To
<7v1vtw367w.fsf@gitster.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
Show 41 quoted lines
> Brent Goodrick <bgoodr@gmail.com> writes:
>
>> Suppose I create a git repo called central.git on a machine I will
>> call "central". In that central.git repo, I put these files:
>>
>>   work.sh
>>   home.sh
>>   generic.sh
>>
>> When I clone the central.git repo on to a different machine I will
>> call "work", I want this fileset to be pulled:
>>
>>   work.sh
>>   generic.sh
>>
>> But not the home.sh file.
>
> You would have one common branch and one branch per deployment.
>
> A common branch would host only common files (e.g. generic.sh file from
> your example).  Per deployment branch, e.g. home, would branch from the
> common branch (so it starts with some version of generic.sh) and may add
> its own private files (e.g. home.sh).
>
> And stick to the following two rules:
>
>  - You make edits to common files only on the common branch.
>  - You merge from common to deployment, never the other way.
>
> So at work, you would have a checkout of your work "deployment branch",
> and find needs to change things.  It is Ok to edit both work.sh and
> generic.sh (without being able to edit both, it would be hard to verify if
> the changes would work together) at this time, but don't commit the result
> in the work branch.
>
> Save the changes to work.sh away (e.g. "git diff work.sh >P.diff" and then
> "git checkout HEAD work.sh"), switch to the common branch, and commit the
> changes to the generic file.  Switch back to the deployment branch, merge
> the common branch (to pick up the changes to home.sh), reapply the changes
> specific to the deployment you saved earlier (e.g. "git apply P.diff"),
> tne commit the result.

By the way, earlier in a different thread, somebody wondered if being able to make a commit on detached HEAD is a good thing, and this is a good example of why it is convenient. When I use the above "one-way merge, never merging back" workflow in real life [*1*], I do not use a simple "git diff work.sh >P.diff && git checkout HEAD work.sh" to save away the tentative changes I made and verified on the deployment branch. The above is an oversimplified example.

For one, in real life projects, there are many files that are specific to individual deployments, and for another, distinction between generic vs deployment specific changes does not cleanly appear at file boundaries.

Instead, I would make a real commit, with full intention of discarding it later.

                  T work
                 /
         ...o---o
               / 
       ...o---o common

I would go back to common branch ("git checkout common"), cherry-pick the commit from the deployment branch ("git cherry-pick --no-commit work"). This would conflict heavily because the common branch does not have any changes specific to the deployment branch (i.e. files that were modified since the deployment forked from the generic, and files the deployment added). That is Ok. I would use "git add -i" and editor to sift out the deployment specific parts to discard, and commit only the parts of the change T made that are truly generic:

                  T work
                 /
         ...o---o
               / 
       ...o---o---A common

Then I would go back to the deployment, and detach the head at commit before the tentative commit T. From here, I can merge the common branch in.

                  T work
                 /
         ...o---o HEAD
               / 
       ...o---o---A common
"git merge common" would make something like this:
                  T work
                 /
         ...o---o---B HEAD
               /   /
       ...o---o---A common

I know that the remainder of the change (i.e. difference between B and T) should be the parts that are specific to the deployment. After reading through the output of "git diff HEAD work" to make sure that it has all deployment specific changes I made (and nothing that should have been in the commit A on common), I would:

	git read-tree -m -u work && git commit
to grow the history of detached HEAD.
                  T work
                 /
         ...o---o---B---C HEAD
               /   /
       ...o---o---A common
After this step, just wrap it up with:
	git branch -f work && git checkout work
to reach the final state:
                  T
                 /
         ...o---o---B---C work
               /   /
       ...o---o---A common

The tentative commit T becomes dangling but we know "diff T C" are empty and records the good state we verified when we made T.

This is one case I still use the plumbing "read-tree -m -u".
[Footnote]
*1* http://gitster.livejournal.com/26540.html
Previous: Brent GoodrickNext: Sitaram Chamarty
Message 6 of 9 in “Is there a way to exclude user-specified files or directories from participating in merges?”
  1. Brent GoodrickFeb 18, 2009
  2. Junio C HamanoFeb 18, 2009
  3. Brent GoodrickFeb 18, 2009
  4. Junio C HamanoFeb 18, 2009
  5. Brent GoodrickFeb 18, 2009
  6. Junio C HamanoFeb 18, 2009
  7. Sitaram ChamartyFeb 18, 2009
  8. Junio C HamanoFeb 18, 2009
  9. Sitaram ChamartyFeb 19, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.