launchdarkly.com
Open in
urlscan Pro
199.232.194.22
Public Scan
Submitted URL: https://em.launchdarkly.com/dc/3xbM4tQLBeNyhupI5OyGykw8MtTro9jKg_eHBeVH-UbDd4IRQLPLCJnuriy92S9ZGDDyo3Elq1yhFfo8D--KTQcF-HU5H...
Effective URL: https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/?utm_source=marketo&utm_medium=email&ut...
Submission: On December 12 via api from IE — Scanned from DE
Effective URL: https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/?utm_source=marketo&utm_medium=email&ut...
Submission: On December 12 via api from IE — Scanned from DE
Form analysis
7 forms found in the DOM<form>
<fieldset>
<legend class="visuallyhidden">Consent Selection</legend>
<div id="CybotCookiebotDialogBodyFieldsetInnerContainer">
<div class="CybotCookiebotDialogBodyLevelButtonWrapper"><label class="CybotCookiebotDialogBodyLevelButtonLabel" for="CybotCookiebotDialogBodyLevelButtonNecessary"><span
class="CybotCookiebotDialogBodyLevelButtonDescription">Necessary</span></label>
<div class="CybotCookiebotDialogBodyLevelButtonSliderWrapper CybotCookiebotDialogBodyLevelButtonSliderWrapperDisabled"><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonNecessary"
class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelButtonDisabled" disabled="disabled" checked="checked"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></div>
</div>
<div class="CybotCookiebotDialogBodyLevelButtonWrapper"><label class="CybotCookiebotDialogBodyLevelButtonLabel" for="CybotCookiebotDialogBodyLevelButtonPreferences"><span
class="CybotCookiebotDialogBodyLevelButtonDescription">Preferences</span></label>
<div class="CybotCookiebotDialogBodyLevelButtonSliderWrapper"><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonPreferences" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox"
data-target="CybotCookiebotDialogBodyLevelButtonPreferencesInline" checked="checked" tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></div>
</div>
<div class="CybotCookiebotDialogBodyLevelButtonWrapper"><label class="CybotCookiebotDialogBodyLevelButtonLabel" for="CybotCookiebotDialogBodyLevelButtonStatistics"><span
class="CybotCookiebotDialogBodyLevelButtonDescription">Statistics</span></label>
<div class="CybotCookiebotDialogBodyLevelButtonSliderWrapper"><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonStatistics" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox"
data-target="CybotCookiebotDialogBodyLevelButtonStatisticsInline" checked="checked" tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></div>
</div>
<div class="CybotCookiebotDialogBodyLevelButtonWrapper"><label class="CybotCookiebotDialogBodyLevelButtonLabel" for="CybotCookiebotDialogBodyLevelButtonMarketing"><span
class="CybotCookiebotDialogBodyLevelButtonDescription">Marketing</span></label>
<div class="CybotCookiebotDialogBodyLevelButtonSliderWrapper"><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonMarketing" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox"
data-target="CybotCookiebotDialogBodyLevelButtonMarketingInline" checked="checked" tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></div>
</div>
</div>
</fieldset>
</form>
<form><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonNecessaryInline" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelButtonDisabled" disabled="disabled" checked="checked"> <span
class="CybotCookiebotDialogBodyLevelButtonSlider"></span></form>
<form><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonPreferencesInline" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox" data-target="CybotCookiebotDialogBodyLevelButtonPreferences"
checked="checked" tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></form>
<form><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonStatisticsInline" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox" data-target="CybotCookiebotDialogBodyLevelButtonStatistics"
checked="checked" tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></form>
<form><input type="checkbox" id="CybotCookiebotDialogBodyLevelButtonMarketingInline" class="CybotCookiebotDialogBodyLevelButton CybotCookiebotDialogBodyLevelConsentCheckbox" data-target="CybotCookiebotDialogBodyLevelButtonMarketing" checked="checked"
tabindex="0"> <span class="CybotCookiebotDialogBodyLevelButtonSlider"></span></form>
<form id="mktoForm_2272" novalidate="novalidate" class="mktoForm mktoHasWidth mktoLayoutLeft" style="font-family: Helvetica, Arial, sans-serif; font-size: 13px; color: rgb(51, 51, 51); width: 181px;"
data-nb-form="72ece616-bea1-4126-a251-1ad050b10253">
<style type="text/css">
.mktoForm .mktoButtonWrap.mktoSimple .mktoButton {
color: #fff;
border: 1px solid #75ae4c;
padding: 0.4em 1em;
font-size: 1em;
background-color: #99c47c;
background-image: -webkit-gradient(linear, left top, left bottom, from(#99c47c), to(#75ae4c));
background-image: -webkit-linear-gradient(top, #99c47c, #75ae4c);
background-image: -moz-linear-gradient(top, #99c47c, #75ae4c);
background-image: linear-gradient(to bottom, #99c47c, #75ae4c);
}
.mktoForm .mktoButtonWrap.mktoSimple .mktoButton:hover {
border: 1px solid #447f19;
}
.mktoForm .mktoButtonWrap.mktoSimple .mktoButton:focus {
outline: none;
border: 1px solid #447f19;
}
.mktoForm .mktoButtonWrap.mktoSimple .mktoButton:active {
background-color: #75ae4c;
background-image: -webkit-gradient(linear, left top, left bottom, from(#75ae4c), to(#99c47c));
background-image: -webkit-linear-gradient(top, #75ae4c, #99c47c);
background-image: -moz-linear-gradient(top, #75ae4c, #99c47c);
background-image: linear-gradient(to bottom, #75ae4c, #99c47c);
}
</style>
<div class="mktoFormRow">
<div class="mktoFieldDescriptor mktoFormCol">
<div class="mktoOffset"></div>
<div class="mktoFieldWrap mktoRequiredField"><label for="Email" id="LblEmail" class="mktoLabel mktoHasWidth">
<div class="mktoAsterix">*</div>
</label>
<div class="mktoGutter mktoHasWidth"></div><input id="Email" name="Email" placeholder="Work Email" maxlength="255" aria-labelledby="LblEmail InstructEmail" type="email" class="mktoField mktoEmailField mktoHasWidth mktoRequired"
aria-required="true" data-nb-id="72ece616-bea1-4126-a251-1ad050b10253"><span id="InstructEmail" tabindex="-1" class="mktoInstruction"></span>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow">
<div class="mktoFieldDescriptor mktoFormCol">
<div class="mktoOffset"></div>
<div class="mktoFieldWrap"><label for="maplesyrup" id="Lblmaplesyrup" class="mktoLabel mktoHasWidth">
<div class="mktoAsterix">*</div>maplesyrup:
</label>
<div class="mktoGutter mktoHasWidth"></div><input id="maplesyrup" name="maplesyrup" maxlength="255" aria-labelledby="Lblmaplesyrup Instructmaplesyrup" type="text" class="mktoField mktoTextField mktoHasWidth"><span id="Instructmaplesyrup"
tabindex="-1" class="mktoInstruction"></span>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="LeadSource" class="mktoField mktoFieldDescriptor mktoFormCol" value="Website">
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="ltutmcampaign" class="mktoField mktoFieldDescriptor mktoFormCol" value="fufn">
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="ltutmcontent" class="mktoField mktoFieldDescriptor mktoFormCol" value="null">
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="ltutmmedium" class="mktoField mktoFieldDescriptor mktoFormCol" value="email">
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="ltutmsource" class="mktoField mktoFieldDescriptor mktoFormCol" value="marketo">
<div class="mktoClear"></div>
</div>
<div class="mktoFormRow"><input type="hidden" name="ltutmterm" class="mktoField mktoFieldDescriptor mktoFormCol" value="text1">
<div class="mktoClear"></div>
</div>
<div class="mktoButtonRow"><span class="mktoButtonWrap mktoSimple"><button type="submit" class="mktoButton">Yes, send me emails</button></span></div><input type="hidden" name="formid" class="mktoField mktoFieldDescriptor" value="2272"><input
type="hidden" name="munchkinId" class="mktoField mktoFieldDescriptor" value="850-KKH-319">
</form>
<form novalidate="novalidate" class="mktoForm mktoHasWidth mktoLayoutLeft" style="font-family: Helvetica, Arial, sans-serif; font-size: 13px; color: rgb(51, 51, 51); visibility: hidden; position: absolute; top: -500px; left: -1000px; width: 1600px;">
</form>
Text Content
Powered by Cookiebot * Consent * Details * [#IABV2SETTINGS#] * About THIS WEBSITE USES COOKIES We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you’ve provided to them or that they’ve collected from your use of their services. Consent Selection Necessary Preferences Statistics Marketing Show details Necessary 86 Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies. Airtable 8 Learn more about this provider __Host-airtable-sessionContains a specific ID for the current session. This is necessary for running the website correctly. Expiry: 1 yearType: HTTP __Host-airtable-session.sigContains a specific ID for the current session. This is necessary for running the website correctly. Expiry: 1 yearType: HTTP AWSALB [x2]Registers which server-cluster is serving the visitor. This is used in context with load balancing, in order to optimize user experience. Expiry: 7 daysType: HTTP AWSALBCORS [x2]Registers which server-cluster is serving the visitor. This is used in context with load balancing, in order to optimize user experience. Expiry: 6 daysType: HTTP brwDetects and logs potential errors on third-party provided functions on the website. Expiry: 1 yearType: HTTP lightstep/clock_state/lightstep.airtable.comNecessary for the website's booking functionality. Expiry: SessionType: HTML Bizible 5 Learn more about this provider _biz_flagsAThis cookie serves multiple purposes; it determines whether the user has submitted any forms, performed cross-domain migration or has made any tracking opt-out choices. Expiry: 1 yearType: HTTP _biz_nACollects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: 1 yearType: HTTP _biz_pendingACollects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: 1 yearType: HTTP _biz_sidCollects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: 1 dayType: HTTP _biz_uidCollects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: 1 yearType: HTTP Codepen 2 Learn more about this provider __cfruid [x2]This cookie is a part of the services provided by Cloudflare - Including load-balancing, deliverance of website content and serving DNS connection for website operators. Expiry: SessionType: HTTP Cookiebot 1 Learn more about this provider CookieConsentStores the user's cookie consent state for the current domain Expiry: 1 yearType: HTTP Crazyegg 2 Learn more about this provider _ce.cchStores the user's cookie consent state for the current domain Expiry: SessionType: HTTP _ce.gtldHolds which URL should be presented to the visitor when visiting the site. Expiry: SessionType: HTTP Google 9 Learn more about this provider test_cookieUsed to check if the user's browser supports cookies. Expiry: 1 dayType: HTTP _GRECAPTCHAThis cookie is used to distinguish between humans and bots. This is beneficial for the website, in order to make valid reports on the use of their website. Expiry: 179 daysType: HTTP NIDRegisters a unique ID that identifies a returning user's device. The ID is used for targeted ads. Expiry: 6 monthsType: HTTP pagead/1p-conversion/#Collects data on visitor behaviour from multiple websites, in order to present more relevant advertisement - This also allows the website to limit the number of times that they are shown the same advertisement. Expiry: SessionType: Pixel rc::aThis cookie is used to distinguish between humans and bots. This is beneficial for the website, in order to make valid reports on the use of their website. Expiry: PersistentType: HTML rc::bThis cookie is used to distinguish between humans and bots. Expiry: SessionType: HTML rc::cThis cookie is used to distinguish between humans and bots. Expiry: SessionType: HTML _ga_#Used by Google Analytics to collect data on the number of times a user has visited the website as well as dates for the first and most recent visit. Expiry: 399 daysType: HTTP _gcl_auUsed by Google AdSense for experimenting with advertisement efficiency across websites using their services. Expiry: 3 monthsType: HTTP Hotjar 6 Learn more about this provider _hjAbsoluteSessionInProgressThis cookie is used to count how many times a website has been visited by different visitors - this is done by assigning the visitor an ID, so the visitor does not get registered twice. Expiry: 1 dayType: HTTP _hjFirstSeenThis cookie is used to determine if the visitor has visited the website before, or if it is a new visitor on the website. Expiry: 1 dayType: HTTP _hjIncludedInPageviewSampleUsed to detect whether the user navigation and interactions are included in the website’s data analytics. Expiry: 1 dayType: HTTP _hjIncludedInSessionSampleRegisters data on visitors' website-behaviour. This is used for internal analysis and website optimization. Expiry: 1 dayType: HTTP _hjSession_#Collects statistics on the visitor's visits to the website, such as the number of visits, average time spent on the website and what pages have been read. Expiry: 1 dayType: HTTP _hjSessionUser_#Collects statistics on the visitor's visits to the website, such as the number of visits, average time spent on the website and what pages have been read. Expiry: 1 yearType: HTTP LaunchDarkly 17 Learn more about this provider @@scroll#Pending Expiry: SessionType: HTML _ce.sCollects data on the user’s navigation and behavior on the website. This is used to compile statistical reports and heatmaps for the website owner. Expiry: 1 yearType: HTTP _CEFTThis cookie is used by the website’s operator in context with multi-variate testing. This is a tool used to combine or change content on the website. This allows the website to find the best variation/edition of the site. Expiry: 1 yearType: HTTP _uetsidCollects data on visitor behaviour from multiple websites, in order to present more relevant advertisement - This also allows the website to limit the number of times that they are shown the same advertisement. Expiry: 1 dayType: HTTP _uetvidUsed to track visitors on multiple websites, in order to present relevant advertisement based on the visitor's preferences. Expiry: 1 yearType: HTTP ce_asset_waitingThis cookie is part of a bundle of cookies which serve the purpose of content delivery and presentation. The cookies keep the correct state of font, blog/picture sliders, color themes and other website settings. Expiry: SessionType: HTML ce_clockSets a timestamp for when the visitor entered the website. This is used for analytical purposes on the website. Expiry: PersistentType: HTML ce_successful_csp_checkDetects whether user behaviour tracking should be active on the website. Expiry: PersistentType: HTML cebsTracks the individual sessions on the website, allowing the website to compile statistical data from multiple visits. This data can also be used to create leads for marketing purposes. Expiry: SessionType: HTTP cebspThis cookie is used to determine when the visitor last visited the different subpages on the website. Expiry: SessionType: HTTP cetabidSets a unique ID for the session. This allows the website to obtain data on visitor behaviour for statistical purposes. Expiry: SessionType: HTML keyval-store#keyvalUsed to maintain visitors' preferences throughout the visit and sub-pages. Expiry: PersistentType: IDB ld:#:#Pending Expiry: PersistentType: HTML ld:#:$diagnosticsPending Expiry: PersistentType: HTML ld:$anonUserIdPending Expiry: PersistentType: HTML PARMONIC_SESSION_IDPending Expiry: PersistentType: HTML ubvtCollects data on the user's visits to the website, such as the number of visits, average time spent on the website and what pages have been loaded with the purpose of generating reports for optimising the website content. Expiry: 2 daysType: HTTP LinkedIn 5 Learn more about this provider lang [x2]Remembers the user's selected language version of a website Expiry: SessionType: HTTP ln_orRegisters statistical data on users' behaviour on the website. Used for internal analytics by the website operator. Expiry: 1 dayType: HTTP li_gcStores the user's cookie consent state for the current domain Expiry: 179 daysType: HTTP lidcUsed by the social networking service, LinkedIn, for tracking the use of embedded services. Expiry: 1 dayType: HTTP Marketo 1 Learn more about this provider _mkto_trkContains data on visitor behaviour and website interaction. This is used in context with the email marketing service Marketo.com, which allows the website to target visitors via email. Expiry: 399 daysType: HTTP Reddit 1 Learn more about this provider _rdt_uuidUsed to track visitors on multiple websites, in order to present relevant advertisement based on the visitor's preferences. Expiry: 3 monthsType: HTTP Segment 2 Learn more about this provider __tld__Used to track visitors on multiple websites, in order to present relevant advertisement based on the visitor's preferences. Expiry: SessionType: HTTP ajs_user_idCollects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: PersistentType: HTML Wistia 2 Learn more about this provider undefinedCollects data on visitor interaction with the website's video-content. This data is used to make the website's video-content more relevant towards the visitor. Expiry: PersistentType: HTML wistiaUsed by the website to track the visitor's use of video-content - The cookie roots from Wistia, which provides video-software to websites. Expiry: PersistentType: HTML app-sj31.marketo.com codepen.io launchdarkly.com vimeo.com 4 __cf_bm [x4]This cookie is used to distinguish between humans and bots. This is beneficial for the website, in order to make valid reports on the use of their website. Expiry: 1 dayType: HTTP app-sj31.marketo.com launchdarkly.com 2 BIGipServer# [x2]Used to distribute traffic to the website on several servers in order to optimise response times. Expiry: SessionType: HTTP cdn.amplitude.com 5 amplitude_#Registers statistical data on users' behaviour on the website. Used for internal analytics by the website operator. Expiry: SessionType: HTTP amplitude_cookie_testDetects whether partner data synchronization is functioning and currently running - This function sends user data between third-party advertisement companies for the purpose of targeted advertisements. Expiry: SessionType: HTTP amplitude_id_#Pending Expiry: SessionType: HTTP amplitude_unsent_#Used in context with the website’s pop-up questionnaires and messengering. The data is used for statistical or marketing purposes. Expiry: PersistentType: HTML amplitude_unsent_identify_#Used in context with the website’s pop-up questionnaires and messengering. The data is used for statistical or marketing purposes. Expiry: PersistentType: HTML j.6sc.co 4 _an_uidPresents the user with relevant content and advertisement. The service is provided by third-party advertisement hubs, which facilitate real-time bidding for advertisers. Expiry: 6 daysType: HTTP _gd_sessionCollects visitor data related to the user's visits to the website, such as the number of visits, average time spent on the website and what pages have been loaded, with the purpose of displaying targeted ads. Expiry: 1 dayType: HTTP _gd_svisitorCollects visitor data related to the user's visits to the website, such as the number of visits, average time spent on the website and what pages have been loaded, with the purpose of displaying targeted ads. Expiry: 399 daysType: HTTP _gd_visitorCollects visitor data related to the user's visits to the website, such as the number of visits, average time spent on the website and what pages have been loaded, with the purpose of displaying targeted ads. Expiry: 399 daysType: HTTP js.qualified.com 2 __q_domainTestPending Expiry: SessionType: HTTP __q_state_BN8NXAwRcuN5KnVdPending Expiry: 399 daysType: HTTP play.google.com www.youtube.com 2 CONSENT [x2]Used to detect if the visitor has accepted the marketing category in the cookie banner. This cookie is necessary for GDPR-compliance of the website. Expiry: 2 yearsType: HTTP web.cvent.com www.google-analytics.com 4 _gat [x2]Used by Google Analytics to throttle request rate Expiry: 1 dayType: HTTP _gid [x2]Registers a unique ID that is used to generate statistical data on how the visitor uses the website. Expiry: 1 dayType: HTTP web.cvent.com www.googletagmanager.com 2 _ga [x2]Registers a unique ID that is used to generate statistical data on how the visitor uses the website. Expiry: 399 daysType: HTTP Preferences 2 Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in. Wistia 2 Learn more about this provider loglevelMaintains settings and outputs when using the Developer Tools Console on current session. Expiry: PersistentType: HTML wistia-video-progress-#Contains a timestamp for the website’s video-content. This allows the user to resume watching without having to start over, if the user leaves the video or website. Expiry: PersistentType: HTML Statistics 13 Statistic cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously. Adobe 1 Learn more about this provider uCollects data on the user's visits to the website, such as the number of visits, average time spent on the website and what pages have been loaded with the purpose of generating reports for optimising the website content. Expiry: SessionType: Pixel Bizible 1 Learn more about this provider m/uCollects data on the user’s navigation and behavior on the website. This is used to compile statistical reports and heatmaps for the website owner. Expiry: SessionType: Pixel Cvent 4 Learn more about this provider _dd_sRegisters the website's speed and performance. This function can be used in context with statistics and load-balancing. Expiry: 1 dayType: HTTP dd_cookie_test_#Registers data on visitors' website-behaviour. This is used for internal analysis and website optimization. Expiry: 1 dayType: HTTP eventguestside-service-sessionPending Expiry: SessionType: HTTP registration-1b38b19d-e697-4c72-bb50-e666089ab6e5Pending Expiry: PersistentType: HTML Fewer & Faster 2 Learn more about this provider _secure_speakerd_sessionPending Expiry: 14 daysType: HTTP beacon.gifPending Expiry: SessionType: Pixel Google 1 Learn more about this provider collectUsed to send data to Google Analytics about the visitor's device and behavior. Tracks the visitor across devices and marketing channels. Expiry: SessionType: Pixel LinkedIn 1 Learn more about this provider AnalyticsSyncHistoryUsed in connection with data-synchronization with third-party analysis service. Expiry: 29 daysType: HTTP Twitter Inc. 1 Learn more about this provider personalization_idThis cookie is set by Twitter - The cookie allows the visitor to share content from the website onto their Twitter profile. Expiry: 399 daysType: HTTP Vimeo 1 Learn more about this provider vuidCollects data on the user's visits to the website, such as which pages have been read. Expiry: 399 daysType: HTTP YouTube 1 Learn more about this provider yt-player-headers-readableUsed to determine the optimal video quality based on the visitor's device and network settings. Expiry: PersistentType: HTML Marketing 39 Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers. Bizible 1 Learn more about this provider m/ipvRegisters user behaviour and navigation on the website, and any interaction with active campaigns. This is used for optimizing advertisement and for efficient retargeting. Expiry: SessionType: Pixel Claritas 1 Learn more about this provider barometric[cuid]Collects data on visitors. This information is used to assign visitors into segments, making website advertisement more efficient. Expiry: 1 yearType: HTTP Codepen 1 Learn more about this provider cp_sessionRegisters user behaviour and navigation on the website, and any interaction with active campaigns. This is used for optimizing advertisement and for efficient retargeting. Expiry: 29 daysType: HTTP Fewer & Faster 1 Learn more about this provider NRBA_SESSION_IDCollects user data through quiz/survey-like content. This allows the website to promote relevant products or services. Expiry: SessionType: HTML Google 5 Learn more about this provider IDEUsed by Google DoubleClick to register and report the website user's actions after viewing or clicking one of the advertiser's ads with the purpose of measuring the efficacy of an ad and to present targeted ads to the user. Expiry: 1 yearType: HTTP pagead/landing [x2]Collects data on visitor behaviour from multiple websites, in order to present more relevant advertisement - This also allows the website to limit the number of times that they are shown the same advertisement. Expiry: SessionType: Pixel pagead/viewthroughconversion/960335887Pending Expiry: SessionType: Pixel ads/ga-audiencesUsed by Google AdWords to re-engage visitors that are likely to convert to customers based on the visitor's online behaviour across websites. Expiry: SessionType: Pixel LinkedIn 3 Learn more about this provider bcookieUsed by the social networking service, LinkedIn, for tracking the use of embedded services. Expiry: 1 yearType: HTTP bscookieUsed by the social networking service, LinkedIn, for tracking the use of embedded services. Expiry: 1 yearType: HTTP UserMatchHistoryEnsures visitor browsing-security by preventing cross-site request forgery. This cookie is essential for the security of the website and visitor. Expiry: 29 daysType: HTTP Quora 1 Learn more about this provider _/ad/75aa344edeef4dbfa3b3dd7cb5f40e6f/pixelCollects data on user behaviour and interaction in order to optimize the website and make advertisement on the website more relevant. Expiry: SessionType: Pixel Reddit 1 Learn more about this provider rp.gifNecessary for the implementation of the Reddit.com's share-button function. Expiry: SessionType: Pixel Soundcloud 1 Learn more about this provider WIDGET::local::assignmentsUsed by audio-platform SoundCloud to implement, measure and improve their embedded content/service on the website - The collection of data also includes visitors’ interaction with embedded content/service. This can be used for statistics or marketing purposes. Expiry: PersistentType: HTML Twitter Inc. 8 Learn more about this provider 1/i/adsct [x2]Pending Expiry: SessionType: Pixel muc_adsCollects data on user behaviour and interaction in order to optimize the website and make advertisement on the website more relevant. Expiry: 399 daysType: HTTP guest_idCollects data related to the user's visits to the website, such as the number of visits, average time spent on the website and which pages have been loaded, with the purpose of personalising and improving the Twitter service. Expiry: 399 daysType: HTTP guest_id_adsCollects information on user behaviour on multiple websites. This information is used in order to optimize the relevance of advertisement on the website. Expiry: 399 daysType: HTTP guest_id_marketingCollects information on user behaviour on multiple websites. This information is used in order to optimize the relevance of advertisement on the website. Expiry: 399 daysType: HTTP i/adsctThe cookie is used by Twitter.com in order to determine the number of visitors accessing the website through Twitter advertisement content. Expiry: SessionType: Pixel i/jotSets a unique ID for the visitor, that allows third party advertisers to target the visitor with relevant advertisement. This pairing service is provided by third party advertisement hubs, which facilitates real-time bidding for advertisers. Expiry: SessionType: Pixel YouTube 12 Learn more about this provider VISITOR_INFO1_LIVETries to estimate the users' bandwidth on pages with integrated YouTube videos. Expiry: 179 daysType: HTTP YSCRegisters a unique ID to keep statistics of what videos from YouTube the user has seen. Expiry: SessionType: HTTP yt.innertube::nextIdRegisters a unique ID to keep statistics of what videos from YouTube the user has seen. Expiry: PersistentType: HTML yt.innertube::requestsRegisters a unique ID to keep statistics of what videos from YouTube the user has seen. Expiry: PersistentType: HTML ytidb::LAST_RESULT_ENTRY_KEYStores the user's video player preferences using embedded YouTube video Expiry: PersistentType: HTML yt-remote-cast-availableStores the user's video player preferences using embedded YouTube video Expiry: SessionType: HTML yt-remote-cast-installedStores the user's video player preferences using embedded YouTube video Expiry: SessionType: HTML yt-remote-connected-devicesStores the user's video player preferences using embedded YouTube video Expiry: PersistentType: HTML yt-remote-device-idStores the user's video player preferences using embedded YouTube video Expiry: PersistentType: HTML yt-remote-fast-check-periodStores the user's video player preferences using embedded YouTube video Expiry: SessionType: HTML yt-remote-session-appStores the user's video player preferences using embedded YouTube video Expiry: SessionType: HTML yt-remote-session-nameStores the user's video player preferences using embedded YouTube video Expiry: SessionType: HTML b.6sc.co 2 6suuidRegisters user behaviour and navigation on the website, and any interaction with active campaigns. This is used for optimizing advertisement and for efficient retargeting. Expiry: 399 daysType: HTTP v1/beacon/img.gifUsed in context with Account-Based-Marketing (ABM). The cookie registers data such as IP-addresses, time spent on the website and page requests for the visit. This is used for retargeting of multiple users rooting from the same IP-addresses. ABM usually facilitates B2B marketing purposes. Expiry: SessionType: Pixel cdn.bizible.com cdn.bizibly.com 2 _BUID [x2]Collects data on visitors' preferences and behaviour on the website - This information is used make content and advertisement more relevant to the specific visitor. Expiry: 1 yearType: HTTP Unclassified 1 Unclassified cookies are cookies that we are in the process of classifying, together with the providers of individual cookies. Airtable 1 Learn more about this provider internal/page_viewPending Expiry: SessionType: Pixel Cross-domain consent[#BULK_CONSENT_DOMAINS_COUNT#] [#BULK_CONSENT_TITLE#] List of domains your consent applies to: [#BULK_CONSENT_DOMAINS#] Cookie declaration last updated on 07.12.22 by Cookiebot [#IABV2_TITLE#] [#IABV2_BODY_INTRO#] [#IABV2_BODY_LEGITIMATE_INTEREST_INTRO#] [#IABV2_BODY_PREFERENCE_INTRO#] [#IABV2_LABEL_PURPOSES#] [#IABV2_BODY_PURPOSES_INTRO#] [#IABV2_BODY_PURPOSES#] [#IABV2_LABEL_FEATURES#] [#IABV2_BODY_FEATURES_INTRO#] [#IABV2_BODY_FEATURES#] [#IABV2_LABEL_PARTNERS#] [#IABV2_BODY_PARTNERS_INTRO#] [#IABV2_BODY_PARTNERS#] Cookies are small text files that can be used by websites to make a user's experience more efficient. The law states that we can store cookies on your device if they are strictly necessary for the operation of this site. For all other types of cookies we need your permission. This site uses different types of cookies. Some cookies are placed by third party services that appear on our pages. You can at any time change or withdraw your consent from the Cookie Declaration on our website. Learn more about who we are, how you can contact us and how we process personal data in our Privacy Policy. Please state your consent ID and date when you contact us regarding your consent. [#OOI_PERSONAL_INFORMATION#] Deny Allow selection Customize Allow all Powered by Cookiebot by Usercentrics For full functionality of this site it is necessary to enable JavaScript. Here are the instructions how to enable JavaScript in your web browser. LaunchDarkly Feature Management Overview What is feature management?What is experimentation?Why LaunchDarkly?Build vs. buyGuide to feature management Platform Core Platform Feature managementExperimentationFeature flagsFeature WorkflowsPlatform architecture Connectivity SDKsAPIsIntegrationsCode References Data AnalyticsData Export Solutions Team DevelopersDevOps & SREMobileProduct managers Use Case All use casesApp modernizationChange and release managementDigital transformation Industry Financial servicesHealthcareU.S. government Resources Explore DocsGuide & tutorialsWebinarsBlogResource centerAcademy Success Stories Case studiesCustomers Enterprise Pricing Sign InGet a Demo LaunchDarkly BlogBlog Best PracticesIndustry InsightsProduct UpdatesTeam & NewsPodcastsMore Get Demo Searching... BEST PRACTICES GIT BRANCHING STRATEGIES VS. TRUNK-BASED DEVELOPMENT By LaunchDarkly • April 14, 2021 14 min read Twitter Facebook LinkedIn Copy Link WHAT IS A BRANCHING STRATEGY? A “branching strategy” refers to the strategy a software development team employs when writing, merging, and shipping code in the context of a version control system like Git. Software developers working as a team on the same codebase must share their changes with each other. But how can they do this efficiently while avoiding malfunctions in their application? The goal of any branching strategy is to solve that problem and to enable teams to work together on the same source code without trampling on each other. A branching strategy defines how a team uses branches to achieve this level of concurrent development. This article will first review the benefits and shortcomings of several common Git branching strategies. Then, we’ll compare those to trunk-based development to learn how the latter solves those shortcomings and enables modern software delivery practices through feature flag management. WHY YOU NEED A BRANCHING STRATEGY A branching strategy ensures everyone on the team is following the same process for making changes to source control. The right strategy enhances collaboration, efficiency, and accuracy in the software delivery process, while the wrong strategy (or no strategy) leads to hours of lost effort. Here are some common use cases to consider when devising a branching strategy. TYPICAL DEVELOPMENT WORKFLOW The typical day-to-day flow includes normal changes that developers make to the code, changes that do not bring any heightened sense of urgency. These changes are ordinary in terms of size and complexity for your codebase and, generally, will make up the bulk of all the changes your developers make. Since this flow will be used the most frequently, your strategy here must ensure proper coordination among the developers and support all relevant policies such as automated testing, pull requests, and deployments. EMERGENCY HOTFIXES An emergency hotfix is when a particular incident or issue has been expedited to deal with some emergent situation, normally bug fixes. Your flow must account for a developer who needs to make an urgent change and get it all the way through your process and into production while still aligning with your typical development workflow. SMALL VS. LARGE CHANGES As the industry has evolved, the emphasis on developers working on smaller changes and limited batch sizes has increased due to broader use of flow-based delivery practices. However, there are still times when you must make large, complex changes, and your branching strategy must accommodate those situations. STANDARD VS. EXPERIMENTAL CHANGES Developers feel greater certainty about how standard code changes will perform than with experimental code changes. For example, if you’re evaluating a new library or framework, you may feel uncertain about how well it integrates with your codebase. In that case, your change may or may not actually go to production but still needs to be shared with other developers. Your branching strategy must account for these types of experimental changes. GIT BRANCHING HOW GIT HANDLES BRANCHES In Git, all branches are simply tags or pointers. Unlike other source control systems, Git doesn’t create copies of files to track changes. Instead, Git tracks all changes as a directed acyclic graph where each node is a set of changes made at one time. Any such node can be a branch, which allows changes to diverge from other parts of the tree. A merge simply modifies the Git object graph without any file-system impacts as in other source control systems. As such, branches in Git are very lightweight to create and manage. COMMON TYPES OF BRANCHES TRUNK BRANCH Every Git repository has a trunk (also referred to as main, mainline, or the master branch). When a Git repository is created, the trunk exists automatically as the implicit first branch. The use of a trunk and the timing of changes landing on it vary depending on the exact branching strategy being used. In trunk-based development, the trunk is the central branch to which all developers send their code changes. DEVELOPMENT BRANCH The development branch is a long-lived feature branch that holds changes made by developers before they’re ready to go to production. It parallels the trunk and is never removed. Some teams have the development branch correspond with a non-production environment. As such, commits to the development branch trigger test environment deployments. Development and trunk are frequently bidirectionally integrated, and it’s typical for a team member to bear the responsibility of integrating them. FEATURE BRANCH A feature branch can be short- or long-lived depending on the specific branching flow. The branch often is used by a single developer for only their changes, but it is possible to share it with other developers as well. Again, the branching strategy will determine how exactly you define a “feature branch”. RELEASE BRANCH A release branch can be either short-lived or long-lived depending on the strategy. In either case, the release branch reflects a set of changes that are intended to go through the production release process. HOTFIX BRANCH A hotfix branch is a branch that’s used generally to hold changes related to emergency bug fixes. They can be short-lived or long-lived, though generally they exist as long-lived branches split off from a release branch. They tend to be more common in teams with explicitly versioned products, such as installed applications. MERGE CONFLICTS AND PAIN It’s easy for development teams to find themselves with a tangled mess of branches that need to be merged with the mainline all at once. And the longer multiple developers keep their code changes from mixing with each other, the higher the risk that those changes will conflict (through changes to common code). It’s changes to common code that prevent Git from handling merges automatically and cause developers to experience the classic horrors of source control management: merge conflicts that waste time, lost changes that vanish entirely, and regression defects from removed code that somehow finds its way back in. Part of why trunk-based development has grown in popularity is because it helps avoid these painful merge conflicts. We’ll unpack trunk-based development in greater detail later. POPULAR BRANCHING FLOWS GITFLOW GitFlow was introduced by Vincent Driessen in 2010 to share insight into the use of Git for source control as its use became more widespread. GitFlow relies on essentially every type of branch that was discussed previously with the bulk of the development workflow centering on the long-lived development branch as a shared integration branch for all the developers. The trunk, in this case, essentially reflects a history of all the changes that have gone to production. PROS AND CONS OF GITFLOW GitFlow made it very easy for developers new to Git to learn and apply its branching model to become productive quickly. In that sense, GitFlow was a great step forward. Unfortunately, as the industry has evolved, some of GitFlow’s underlying flaws have been exposed. The sheer volume of branches, especially long-lived branches, is a large maintenance headache for a team. A team without the proper discipline to keep feature branches small and short-lived will experience considerable challenges in merging into the development branch, with each subsequent developer having to deal with more and more potential merge conflicts. Additionally, the level of effort needed to maintain the branches adds overhead to the team. In 2020, Driessen himself suggested as an addendum to his original post that GitHub Flow was likely a much better starting point for most software teams today than GitFlow due to the surge in web-delivered software as a service instead of installed software. GITHUB FLOW GitHub Flow was popularized by GitHub as a simpler alternative to GitFlow. It calls for the following workflow: * Trunk is always releasable, and in fact, releases are generally done directly from it. * Each developer creates a new branch, the feature branch, for their changes from trunk. * Feature branches can be deployed to a testing environment for verification or pushed directly to trunk and deployed to a non-production environment from there. * A short-lived release branch may be used off trunk to prepare for and execute a release. PROS AND CONS OF GITHUB FLOW Because GitHub Flow treats every change as a feature branch, it has considerably fewer moving parts than GitFlow. The only long-lived branch is trunk, so branch maintenance is far less of a burden. However, an undisciplined team that has feature branches open for several days can still run into merge troubles, and now, those troubles will directly impact the trunk. A bad merge on trunk can leave it in an undeployable state, which is a big no-no in this flow. CHALLENGES Both of these branching strategies can work for the right environment, but they have similar downsides. The biggest downside is neither flow adequately supports Continuous Integration. And Continuous Integration is becoming an essential modern development practice. By relying on feature branches, it’s too easy to focus on the benefits of change isolation and ignore the costs. Instead, a better strategy would support Continuous Integration, wherein developers integrate code regularly (i.e., at least every day). Fortunately, there is a branching strategy able to meet all these needs: trunk-based development. TRUNK-BASED DEVELOPMENT Trunk-based development (TBD) is a branching strategy where all developers integrate their changes directly to a shared trunk every day, a shared trunk that is always in a releasable state. No matter what a developer might do on their local repository, at least once each day, they must integrate their code. This practice forces each developer to regularly see and react to the changes being made by their teammates in version control, which drives collaboration around the quality and state of the codebase as a near-constant activity. TBD allows for the use of other branches, such as a short-lived release branch off the trunk for executing a release and local-only feature branches, but neither are required to practice TBD. As Continuous Delivery and DevOps have become increasingly prominent and even necessary for many software development teams, TBD has the tightest alignment with those modern delivery approaches. In fact, trunk-based development is a prerequisite for CI/CD. BENEFITS OF TRUNK-BASED DEVELOPMENT OVER FEATURE BRANCHING TRUE CONTINUOUS INTEGRATION TBD puts continuous integration front and center in a developer’s workflow. There’s really no way to avoid it without breaking the team’s policy on using TBD. You simply must integrate your changes every day; realizing that instantly makes you think differently about how you approach your work and your collaboration with your team members. And continuously integrating code changes is essential to innovating at a faster pace. SMALL CHANGES Integrating changes every day means that you must take small steps forward. You cannot start your work by making a sweeping set of changes in a lot of code files that breaks your local compilation. Instead, you must see your work as a series of small steps forward where each step could be released to production. By implementing smaller changes, you limit the blast radius of any changes that cause a problem in production. BRANCH BY ABSTRACTION For most developers, the previous two concepts make sense and generally are hard to argue with. In practice, though, it becomes challenging when a new feature is simply too big to be done in one day. At that point, the need to integrate changes seems impossible. The TBD solution is “branch by abstraction”, a practice to help developers continue to make and integrate small changes every day even if the overall feature still takes several days to complete. In trunk-based development, first, you’ll identify the areas where you need to make some changes. Next, you’ll find the point in the code where you can toggle over to different logic. Then, you’ll introduce a new component or interface to establish a seam to capture your changes. As you integrate your changes with trunk, your new code will be integrated to the shared trunk in version control (and could even be deployed), but you haven’t yet wired the code into the working system so it’s not actually being used. Ultimately, when all your changes are completed, you’d wire in your new components and remove the old components. This technique is called branching by abstraction: you rely on a source code abstraction to achieve the effect of a branch without an actual version control branch. FEATURE FLAGS As you become comfortable with branch by abstraction, you’ll realize that sometimes you do want your code changes to be deployed. For example, you may want your changes to go to a non-production environment for verification, but not yet be visible in production. Or maybe you want a limited set of users to see your changes in production (e.g., in a canary launch) but not the entire customer base. You could achieve this with branch by abstraction, but attempting to control environmental configuration in source control is both a mismatch and inflexible. Instead, feature flags allow you to wire your branch by abstraction to an externally controllable mechanism, such as an application configuration file or even an external database or service. This gives more control over releasing your change outside the codebase itself. Feature flags allow developers to deploy unfinished code to production while hiding it from end-users. Feature flags thus reduce risk when doing trunk-based development. HOW FEATURE FLAGS ENABLE TRUNK-BASED DEVELOPMENT FLAGS FOR DEVELOPMENT ONLY A common situation in TBD is wanting changes to be visible in a development environment for testing, but not to be visible in production. Since, by definition in TBD, any changes in trunk can go to production, you must distinguish deployed (code moved to an environment) from released (visible in an environment). The typical first step is to link an application configuration setting to your branch by abstraction seam. The configuration can be managed by a build system to release your changes in a non-production environment and keep them disabled in production. This technique gives you the confidence that your changes won’t be prematurely released to production while still letting them be released elsewhere. FLAGS FOR DEPLOYMENT GATING Having mastered the use of feature flags to manage releases between non-production and production environments, the next step is to perform an incremental release of changes into production. For example, you may do a canary release, in which you start by releasing a change in production to internal or pilot users only, or only to a certain geography. You then observe the impact of that change in production, and based on those observations, you release the changes to more and more users until eventually they’re released to your entire customer population. The challenge here is using feature flags that provide the granularity you’re after and to manage them in a low-overhead way. Continually changing the build system to facilitate releases around feature flags will quickly become taxing for a build engineering or DevOps team. And while many engineering teams may think that they could build their own feature flag management system, they probably shouldn’t. Building such a system takes focus away from the core competency of the organization and the team. Instead, a software development team will ultimately want the benefits of this level of feature flag management, but as a service. LAUNCHDARKLY FOR STRATEGIC FLAG MANAGEMENT LaunchDarkly is such a feature flag management provider, and it enables you to do TBD with feature flags. In LaunchDarkly, you can set up feature flags to control releases in almost any way you would need. LaunchDarkly supports many of the elements that are essential to an organizational release such as scheduling a feature flag update, implementing approvals of feature flag updates, integrating feature flag changes with other external metrics or events, and so on. Ultimately, LaunchDarkly allows software organizations to use feature flags in sophisticated ways on a large scale. And it is a key driver of trunk-based development. CONCLUSION More and more software development teams are looking to speed up release cadences to get changes into customers’ hands faster than ever before. This goal exposes the high overhead associated with more classic branching strategies as well as the lack of built-in, granular control over releases. Trunk-based development is the best enabler for improving your code quality through better developer collaboration and real continuous integration. LaunchDarkly takes TBD to the next level by providing feature flags as a service to seamlessly link in-progress and completed features with dynamic releases. By LaunchDarkly Twitter Facebook LinkedIn Copy Link You May Like BEST PRACTICESTesting in Production to Stay Safe and Sensible BEST PRACTICESWhat Is Continuous Testing? A Straightforward Introduction DECEMBER 6, 2022 • BEST PRACTICESHow to Get the Most from Our Datadog Integrations DECEMBER 6, 2022 • INDUSTRY INSIGHTSWhat is a Kill Switch in Software Development? DECEMBER 1, 2022 • INDUSTRY INSIGHTSThe Role of the Release Manager in DevOps NOVEMBER 29, 2022 • BEST PRACTICESUsing LaunchDarkly in AWS Serverless INBOXES LOVE LAUNCHDARKLY. Make sure you get all the content, tips, and news you can use. * * maplesyrup: Yes, send me emails WE EMPOWER ALL TEAMS TO DELIVER AND CONTROL THEIR SOFTWARE. Support * Support Home * Request Support * Documentation * Status Why Us * ROI of feature management * Trust & security * Implementation * LaunchDarkly vs. competitors * LaunchDarkly on AWS * Economic impact of LaunchDarkly Learn * Case studies * Webinars * Events * Blog * Podcast * Trajectory * Galaxy Company * About us * Careers * Press and analysts * Partner program * Terms & Policies * Contact us * LaunchDarkly.org ©2022 Catamorphic Co. Twitter LinkedIn Meetup YouTube Instagram LaunchDarkly BlogClose Best PracticesIndustry InsightsProduct UpdatesTeam & NewsPodcasts